2727using Serilog ;
2828using System . Globalization ;
2929using System . Runtime . CompilerServices ;
30+ using OpenpilotSdk . OpenPilot . Segment ;
3031
3132namespace OpenpilotSdk . Hardware
3233{
@@ -131,10 +132,32 @@ public async Task DeleteDriveAsync(Drive drive)
131132 await Task . WhenAll ( deleteTasks ) ;
132133 }
133134
134- public async Task ExportDriveAsync ( string exportPath , Drive drive , Camera camera , bool combineSegments = false , IProgress < int > progress = null )
135+ public async Task ExportDriveAsync ( string exportPath , Drive drive , Camera camera , bool combineSegments = false , IProgress < OpenPilot . Camera . Progress > progress = null )
135136 {
136137 await ConnectAsync ( ) ;
137138
139+ var cameraProgress = new OpenPilot . Camera . Progress ( camera ) ;
140+ Progress < Progress > segmentProgress = null ;
141+ if ( progress != null )
142+ {
143+ segmentProgress = new Progress < Progress > ( ) ;
144+ var segmentProgressDictionary = drive . Segments . ToDictionary ( segment => segment . Index , _ => 0 ) ;
145+ int previousProgress = 0 ;
146+ segmentProgress . ProgressChanged += async ( sender , segmentProgressResult ) =>
147+ {
148+ segmentProgressDictionary [ segmentProgressResult . Segment ] = segmentProgressResult . Percent ;
149+
150+ cameraProgress . Percent = ( segmentProgressDictionary . Sum ( segment => segment . Value ) * 100 ) /
151+ ( segmentProgressDictionary . Count * 100 ) ;
152+
153+ if ( cameraProgress . Percent > previousProgress )
154+ {
155+ previousProgress = cameraProgress . Percent ;
156+ progress . Report ( cameraProgress ) ;
157+ }
158+ } ;
159+ }
160+
138161 if ( ! Directory . Exists ( exportPath ) )
139162 {
140163 Directory . CreateDirectory ( exportPath ) ;
@@ -143,7 +166,7 @@ public async Task ExportDriveAsync(string exportPath, Drive drive, Camera camera
143166 if ( combineSegments )
144167 {
145168 var exportTasks =
146- drive . Segments . Select ( ( segment ) => ExportSegmentAsync ( exportPath , segment , camera , false ) ) . ToArray ( ) ;
169+ drive . Segments . Select ( ( segment ) => ExportSegmentAsync ( exportPath , segment , camera , false , segmentProgress ) ) . ToArray ( ) ;
147170
148171 if ( exportTasks . Length > 0 )
149172 {
@@ -166,11 +189,6 @@ public async Task ExportDriveAsync(string exportPath, Drive drive, Camera camera
166189 }
167190 File . Delete ( tempFilePath ) ;
168191 }
169-
170- if ( progress != null )
171- {
172- progress . Report ( i ) ;
173- }
174192 }
175193
176194 fileWritten = outputFile . Length > 0 ;
@@ -191,7 +209,8 @@ await FFMpegArguments.FromFileInput(outputFilePath, true,
191209 var m3uFileName = drive . ToString ( ) + ( char ) camera . Type + ".m3u" ;
192210
193211 var exportTasks =
194- drive . Segments . Select ( ( segment ) => ExportSegmentAsync ( exportPath , segment , camera , true , progress ) ) ;
212+ drive . Segments . Select ( ( segment ) => ExportSegmentAsync ( exportPath , segment , camera , true , segmentProgress ) ) . ToArray ( ) ;
213+
195214 var exportedSegments = ( await Task . WhenAll ( exportTasks ) ) . Where ( file => ! string . IsNullOrWhiteSpace ( file ) ) . ToArray ( ) ;
196215
197216 if ( exportedSegments . Length > 1 )
@@ -228,8 +247,10 @@ public void ExportDrive(string path, Drive drive, IProgress<int> progress = null
228247 }
229248
230249 public async Task < string > ExportSegmentAsync ( string path , DriveSegment driveSegment , Camera camera , bool containerize ,
231- IProgress < int > progress = null )
250+ IProgress < Progress > progress = null )
232251 {
252+ var segmentProgress = new Progress ( driveSegment . Index ) ;
253+
233254 Video video = null ;
234255 switch ( camera . Type )
235256 {
@@ -284,7 +305,28 @@ public async Task<string> ExportSegmentAsync(string path, DriveSegment driveSegm
284305 await using ( var stream = await sftpClient . OpenAsync ( videoPath , FileMode . Open ,
285306 FileAccess . Read , CancellationToken . None ) )
286307 {
287- await stream . CopyToAsync ( outputFile ) ;
308+ var buffer = new byte [ 81920 ] ;
309+ int bytesRead = 0 ;
310+ var sourceLength = stream . Length ;
311+ int totalBytesRead = 0 ;
312+ int previousProgress = 0 ;
313+
314+ while ( ( bytesRead = await stream . ReadAsync ( buffer , 0 , buffer . Length ) . ConfigureAwait ( false ) ) > 0 )
315+ {
316+ await outputFile . WriteAsync ( buffer , 0 , bytesRead ) . ConfigureAwait ( false ) ;
317+
318+ if ( progress != null )
319+ {
320+ totalBytesRead += bytesRead ;
321+
322+ segmentProgress . Percent = ( int ) ( ( ( double ) totalBytesRead / ( double ) sourceLength ) * 100 ) ;
323+ if ( segmentProgress . Percent > previousProgress )
324+ {
325+ previousProgress = segmentProgress . Percent ;
326+ progress . Report ( segmentProgress ) ;
327+ }
328+ }
329+ }
288330 }
289331 }
290332 }
@@ -304,7 +346,8 @@ await FFMpegArguments.FromFileInput(outputFilePath, true,
304346
305347 if ( progress != null )
306348 {
307- progress . Report ( driveSegment . Index ) ;
349+ segmentProgress . Percent = 100 ;
350+ progress . Report ( segmentProgress ) ;
308351 }
309352
310353 return fileName ;
0 commit comments