@@ -44,12 +44,13 @@ public async Task<string> Downmux(MediaSourceInfo mediaSource, CancellationToken
4444 "-dn" ,
4545 "-c:v copy" ,
4646 "-f hevc" , // trivia: using the hevc muxer automatically adds the hevc_mp4toannexb bitstream filter
47- ffmpegOutputPath
47+ "-"
4848 ] ) ,
49- RedirectStandardError = true
49+ RedirectStandardError = true ,
50+ RedirectStandardOutput = true
5051 }
5152 } ;
52-
53+
5354 _logger . LogInformation ( "{Command} {Arguments}" , ffmpeg . StartInfo . FileName , ffmpeg . StartInfo . Arguments ) ;
5455 ffmpeg . Start ( ) ;
5556
@@ -58,9 +59,7 @@ public async Task<string> Downmux(MediaSourceInfo mediaSource, CancellationToken
5859 ffmpeg ,
5960 token )
6061 . ConfigureAwait ( false ) ;
61-
62- await ffmpeg . WaitForExitAsync ( ) . ConfigureAwait ( false ) ;
63-
62+
6463 // and feed it into dovi_tool, discarding the enhancement layer
6564 using var doviTool = new Process ( )
6665 {
@@ -70,13 +69,14 @@ public async Task<string> Downmux(MediaSourceInfo mediaSource, CancellationToken
7069 "-m 2" , // convert RPU to 8.1
7170 "convert" , // modify RPU
7271 "--discard" , // discard EL
73- $ "--input { ffmpegOutputPath } ",
74- $ "--output { doviToolOutputPath } "
72+ $ "-",
73+ $ "-o { doviToolOutputPath } "
7574 ] ) ,
75+ RedirectStandardInput = true ,
7676 RedirectStandardError = true
7777 }
7878 } ;
79-
79+
8080 _logger . LogInformation ( "{Command} {Arguments}" , doviTool . StartInfo . FileName , doviTool . StartInfo . Arguments ) ;
8181 doviTool . Start ( ) ;
8282
@@ -86,18 +86,42 @@ public async Task<string> Downmux(MediaSourceInfo mediaSource, CancellationToken
8686 token )
8787 . ConfigureAwait ( false ) ;
8888
89- await doviTool . WaitForExitAsync ( ) ;
89+ var pipeTask = Task . Run ( ( ) =>
90+ {
91+ var buffer = new byte [ 4 * 1024 * 1024 ] ;
92+
93+ while ( ! token . IsCancellationRequested
94+ && ffmpeg . StandardOutput . BaseStream . CanRead
95+ && doviTool . StandardInput . BaseStream . CanWrite )
96+ {
97+ var bytesRead = ffmpeg . StandardOutput . BaseStream . Read ( buffer , 0 , 4 * 1024 * 1024 ) ;
98+ if ( bytesRead <= 0 )
99+ {
100+ break ;
101+ }
102+
103+ doviTool . StandardInput . BaseStream . Write ( buffer , 0 , bytesRead ) ;
104+ doviTool . StandardInput . BaseStream . Flush ( ) ;
105+ }
90106
91- try
107+ doviTool . StandardInput . BaseStream . Close ( ) ;
108+ } , token )
109+ . ContinueWith ( t =>
92110 {
93- if ( ! File . Exists ( doviToolOutputPath ) )
111+ if ( t . IsFaulted )
94112 {
95- throw new Exception ( "dovi_tool failed" ) ;
113+ ffmpeg . Kill ( ) ;
114+ doviTool . Kill ( ) ;
96115 }
97- }
98- finally
116+ } ) ;
117+
118+ await Task . WhenAll ( RunToExit ( ffmpeg ) ,
119+ RunToExit ( doviTool ) ,
120+ pipeTask ) ;
121+
122+ if ( ! File . Exists ( doviToolOutputPath ) )
99123 {
100- File . Delete ( ffmpegOutputPath ) ;
124+ throw new Exception ( "HEVC extraction failed" ) ;
101125 }
102126
103127 // then remux the HEVC stream into an MP4 with the right DoVi side data
@@ -119,7 +143,7 @@ public async Task<string> Downmux(MediaSourceInfo mediaSource, CancellationToken
119143 RedirectStandardError = true
120144 }
121145 } ;
122-
146+
123147 _logger . LogInformation ( "{Command} {Arguments}" , mp4box . StartInfo . FileName , mp4box . StartInfo . Arguments ) ;
124148 mp4box . Start ( ) ;
125149
@@ -129,11 +153,24 @@ public async Task<string> Downmux(MediaSourceInfo mediaSource, CancellationToken
129153 token )
130154 . ConfigureAwait ( false ) ;
131155
132- await mp4box . WaitForExitAsync ( token ) ;
156+ await RunToExit ( mp4box ) ;
133157
134158 File . Delete ( doviToolOutputPath ) ;
135159
136160 return mp4boxOutputPath ;
161+
162+ async Task RunToExit ( Process p )
163+ {
164+ try
165+ {
166+ await p . WaitForExitAsync ( token ) . ConfigureAwait ( false ) ;
167+ }
168+ catch ( OperationCanceledException )
169+ {
170+ p . Kill ( ) ;
171+ throw ;
172+ }
173+ }
137174 }
138175
139176 private async Task WriteStreamToLog ( string logPath , Stream logStream , Process logProcess , CancellationToken token )
0 commit comments