@@ -80,7 +80,7 @@ public class HandBrakeInstance : IDisposable
8080 /// <summary>
8181 /// The current encode job for this instance.
8282 /// </summary>
83- private EncodeJob job ;
83+ private EncodeJob currentJob ;
8484
8585 /// <summary>
8686 /// True if the current job is scanning for subtitles.
@@ -288,16 +288,80 @@ public BitmapImage GetPreview(EncodeJob job, int previewNumber)
288288 /// <returns>The video bitrate in kbps.</returns>
289289 public int CalculateBitrate ( EncodeJob job , int sizeMB )
290290 {
291- hb_title_s title = this . GetOriginalTitle ( job . Title ) ;
291+ long availableBytes = sizeMB * 1024 * 1024 ;
292292
293- hb_job_s nativeJob = InteropUtilities . ReadStructure < hb_job_s > ( title . job ) ;
294- List < IntPtr > allocatedMemory = this . ApplyJob ( ref nativeJob , job ) ;
293+ EncodingProfile profile = job . EncodingProfile ;
294+ Title title = this . GetTitle ( job . Title ) ;
295295
296- int calculatedBitrate = HbLib . hb_calc_bitrate ( ref nativeJob , sizeMB ) ;
296+ double lengthSeconds = HandBrakeUtils . GetJobLengthSeconds ( job , title ) ;
297+ lengthSeconds += 1.5 ;
297298
298- InteropUtilities . FreeMemory ( allocatedMemory ) ;
299+ double outputFramerate ;
300+ if ( profile . Framerate == 0 )
301+ {
302+ outputFramerate = title . Framerate ;
303+ }
304+ else
305+ {
306+ // Not sure what to do for VFR here hb_calc_bitrate never handled it...
307+ // just use the peak for now.
308+ outputFramerate = profile . Framerate ;
309+ }
310+
311+ long frames = ( long ) ( lengthSeconds * outputFramerate ) ;
312+
313+ availableBytes -= frames * HandBrakeUtils . ContainerOverheadPerFrame ;
314+
315+ List < Tuple < AudioEncoding , int > > outputTrackList = this . GetOutputTracks ( job ) ;
316+ availableBytes -= HandBrakeUtils . GetAudioSize ( job , lengthSeconds , title , outputTrackList ) ;
317+
318+ if ( availableBytes < 0 )
319+ {
320+ return 0 ;
321+ }
299322
300- return calculatedBitrate ;
323+ // Video bitrate is in kilobits per second, or where 1 kbps is 1000 bits per second.
324+ // So 1 kbps is 125 bytes per second.
325+ return ( int ) ( availableBytes / ( 125 * lengthSeconds ) ) ;
326+ }
327+
328+ /// <summary>
329+ /// Gives estimated file size (in MB) of the given job and video bitrate.
330+ /// </summary>
331+ /// <param name="job">The encode job.</param>
332+ /// <param name="videoBitrate">The video bitrate to be used (kbps).</param>
333+ /// <returns>The estimated file size (in MB) of the given job and video bitrate.</returns>
334+ public double CalculateFileSize ( EncodeJob job , int videoBitrate )
335+ {
336+ long totalBytes = 0 ;
337+
338+ EncodingProfile profile = job . EncodingProfile ;
339+ Title title = this . GetTitle ( job . Title ) ;
340+
341+ double lengthSeconds = HandBrakeUtils . GetJobLengthSeconds ( job , title ) ;
342+ lengthSeconds += 1.5 ;
343+
344+ double outputFramerate ;
345+ if ( profile . Framerate == 0 )
346+ {
347+ outputFramerate = title . Framerate ;
348+ }
349+ else
350+ {
351+ // Not sure what to do for VFR here hb_calc_bitrate never handled it...
352+ // just use the peak for now.
353+ outputFramerate = profile . Framerate ;
354+ }
355+
356+ long frames = ( long ) ( lengthSeconds * outputFramerate ) ;
357+
358+ totalBytes += ( long ) ( lengthSeconds * videoBitrate * 125 ) ;
359+ totalBytes += frames * HandBrakeUtils . ContainerOverheadPerFrame ;
360+
361+ List < Tuple < AudioEncoding , int > > outputTrackList = this . GetOutputTracks ( job ) ;
362+ totalBytes += HandBrakeUtils . GetAudioSize ( job , lengthSeconds , title , outputTrackList ) ;
363+
364+ return ( double ) totalBytes / 1024 / 1024 ;
301365 }
302366
303367 /// <summary>
@@ -318,7 +382,7 @@ public void StartEncode(EncodeJob jobToStart)
318382 /// <param name="previewSeconds">The number of seconds in the preview.</param>
319383 public void StartEncode ( EncodeJob job , bool preview , int previewNumber , int previewSeconds )
320384 {
321- this . job = job ;
385+ this . currentJob = job ;
322386 hb_job_s nativeJob = InteropUtilities . ReadStructure < hb_job_s > ( this . GetOriginalTitle ( job . Title ) . job ) ;
323387 this . encodeAllocatedMemory = this . ApplyJob ( ref nativeJob , job , preview , previewNumber , previewSeconds ) ;
324388
@@ -484,7 +548,7 @@ public void GetSize(EncodeJob job, out int width, out int height, out int parWid
484548 return ;
485549 }
486550
487- hb_job_s nativeJob = InteropUtilities . ReadStructure < hb_job_s > ( this . GetOriginalTitle ( job . Title ) . job ) ;
551+ var nativeJob = InteropUtilities . ReadStructure < hb_job_s > ( this . GetOriginalTitle ( job . Title ) . job ) ;
488552 List < IntPtr > allocatedMemory = this . ApplyJob ( ref nativeJob , job , false , 0 , 0 ) ;
489553
490554 int refWidth = 0 ;
@@ -541,7 +605,7 @@ protected virtual void Dispose(bool disposing)
541605 /// </summary>
542606 private void PollScanProgress ( )
543607 {
544- hb_state_s state = new hb_state_s ( ) ;
608+ var state = new hb_state_s ( ) ;
545609 HbLib . hb_get_state ( this . hbHandle , ref state ) ;
546610
547611 if ( state . state == NativeConstants . HB_STATE_SCANNING )
@@ -568,7 +632,7 @@ private void PollScanProgress()
568632
569633 if ( this . originalTitles . Count > 0 )
570634 {
571- hb_job_s nativeJob = InteropUtilities . ReadStructure < hb_job_s > ( this . originalTitles [ 0 ] . job ) ;
635+ var nativeJob = InteropUtilities . ReadStructure < hb_job_s > ( this . originalTitles [ 0 ] . job ) ;
572636 this . featureTitle = nativeJob . feature ;
573637 }
574638 else
@@ -600,7 +664,7 @@ private void PollEncodeProgress()
600664 int pass = 1 ;
601665 int rawJobNumber = state . param . working . job_cur ;
602666
603- if ( this . job . EncodingProfile . TwoPass )
667+ if ( this . currentJob . EncodingProfile . TwoPass )
604668 {
605669 if ( this . subtitleScan )
606670 {
@@ -995,25 +1059,12 @@ private List<IntPtr> ApplyJob(ref hb_job_s nativeJob, EncodeJob job, bool previe
9951059
9961060 var audioList = new List < hb_audio_s > ( ) ;
9971061 int numTracks = 0 ;
998- foreach ( AudioEncoding encoding in profile . AudioEncodings )
1062+
1063+ List < Tuple < AudioEncoding , int > > outputTrackList = this . GetOutputTracks ( job ) ;
1064+
1065+ foreach ( Tuple < AudioEncoding , int > outputTrack in outputTrackList )
9991066 {
1000- if ( encoding . InputNumber == 0 )
1001- {
1002- // Add this encoding for all chosen tracks
1003- foreach ( int chosenTrack in job . ChosenAudioTracks )
1004- {
1005- if ( titleAudio . Count >= chosenTrack )
1006- {
1007- audioList . Add ( ConvertAudioBack ( encoding , titleAudio [ chosenTrack - 1 ] , chosenTrack , numTracks ++ , allocatedMemory ) ) ;
1008- }
1009- }
1010- }
1011- else if ( encoding . InputNumber <= job . ChosenAudioTracks . Count )
1012- {
1013- // Add this encoding for the specified track, if it exists
1014- int trackNumber = job . ChosenAudioTracks [ encoding . InputNumber - 1 ] ;
1015- audioList . Add ( ConvertAudioBack ( encoding , titleAudio [ trackNumber - 1 ] , trackNumber , numTracks ++ , allocatedMemory ) ) ;
1016- }
1067+ audioList . Add ( ConvertAudioBack ( outputTrack . Item1 , titleAudio [ outputTrack . Item2 - 1 ] , outputTrack . Item2 , numTracks ++ , allocatedMemory ) ) ;
10171068 }
10181069
10191070 NativeList nativeAudioList = InteropUtilities . ConvertListBack < hb_audio_s > ( audioList ) ;
@@ -1152,6 +1203,36 @@ private List<IntPtr> ApplyJob(ref hb_job_s nativeJob, EncodeJob job, bool previe
11521203 return allocatedMemory ;
11531204 }
11541205
1206+ /// <summary>
1207+ /// Gets a list of encodings and target track indices (1-based).
1208+ /// </summary>
1209+ /// <param name="job">The encode job</param>
1210+ /// <returns>A list of encodings and target track indices (1-based).</returns>
1211+ private List < Tuple < AudioEncoding , int > > GetOutputTracks ( EncodeJob job )
1212+ {
1213+ var list = new List < Tuple < AudioEncoding , int > > ( ) ;
1214+
1215+ foreach ( AudioEncoding encoding in job . EncodingProfile . AudioEncodings )
1216+ {
1217+ if ( encoding . InputNumber == 0 )
1218+ {
1219+ // Add this encoding for all chosen tracks
1220+ foreach ( int chosenTrack in job . ChosenAudioTracks )
1221+ {
1222+ list . Add ( new Tuple < AudioEncoding , int > ( encoding , chosenTrack ) ) ;
1223+ }
1224+ }
1225+ else if ( encoding . InputNumber <= job . ChosenAudioTracks . Count )
1226+ {
1227+ // Add this encoding for the specified track, if it exists
1228+ int trackNumber = job . ChosenAudioTracks [ encoding . InputNumber - 1 ] ;
1229+ list . Add ( new Tuple < AudioEncoding , int > ( encoding , trackNumber ) ) ;
1230+ }
1231+ }
1232+
1233+ return list ;
1234+ }
1235+
11551236 /// <summary>
11561237 /// Adds a filter to the given filter list.
11571238 /// </summary>
@@ -1373,7 +1454,8 @@ private Title ConvertTitle(hb_title_s title)
13731454 LanguageCode = audio . config . lang . iso639_2 ,
13741455 Description = audio . config . lang . description ,
13751456 ChannelLayout = audio . config . input . channel_layout ,
1376- SampleRate = audio . config . input . samplerate
1457+ SampleRate = audio . config . input . samplerate ,
1458+ Bitrate = audio . config . input . bitrate
13771459 } ;
13781460
13791461 newTitle . AudioTracks . Add ( newAudio ) ;
0 commit comments