+ if( ( job->sequence_id & 0xFFFFFF ) != ( interjob->last_job & 0xFFFFFF) )
+ return; // Interjob information is for a different encode.
+
+ /* Cache the original framerate before altering it. */
+ interjob->vrate = job->vrate;
+ interjob->vrate_base = job->vrate_base;
+
+ real_frames = interjob->frame_count - interjob->render_dropped;
+
+ job->vrate = job->vrate_base * ( (double)real_frames * 90000 / interjob->total_time );
+}
+
+/**
+ * Job initialization rountine.
+ * Initializes fifos.
+ * Creates work objects for synchronizer, video decoder, video renderer, video decoder, audio decoder, audio encoder, reader, muxer.
+ * Launches thread for each work object with work_loop.
+ * Loops while monitoring status of work threads and fifos.
+ * Exits loop when conversion is done and fifos are empty.
+ * Closes threads and frees fifos.
+ * @param job Handle work hb_job_t.
+ * @param cpu_count number of CPUs found in system.
+ */
+static void do_job( hb_job_t * job, int cpu_count )
+{
+ hb_title_t * title;
+ int i, j;
+ hb_work_object_t * w;
+ hb_work_object_t * sync;
+ hb_work_object_t * muxer;
+ hb_interjob_t * interjob;
+
+ hb_audio_t * audio;
+ hb_subtitle_t * subtitle;
+ hb_attachment_t * attachment;
+ unsigned int subtitle_highest = 0;
+ unsigned int subtitle_highest_id = 0;
+ unsigned int subtitle_lowest = -1;
+ unsigned int subtitle_lowest_id = 0;
+ unsigned int subtitle_forced_id = 0;
+ unsigned int subtitle_hit = 0;
+
+ title = job->title;
+ interjob = hb_interjob_get( job->h );
+
+ if( job->pass == 2 && !job->cfr )
+ {
+ correct_framerate( job );
+ }
+
+ job->list_work = hb_list_init();
+
+ hb_log( "starting job" );
+
+ if( job->anamorphic.mode )
+ {
+ hb_set_anamorphic_size(job, &job->width, &job->height, &job->anamorphic.par_width, &job->anamorphic.par_height);
+
+ if( job->vcodec == HB_VCODEC_FFMPEG )
+ {
+ /* Just to make working with ffmpeg even more fun,
+ lavc's MPEG-4 encoder can't handle PAR values >= 255,
+ even though AVRational does. Adjusting downwards
+ distorts the display aspect slightly, but such is life. */
+ while ((job->anamorphic.par_width & ~0xFF) ||
+ (job->anamorphic.par_height & ~0xFF))
+ {
+ job->anamorphic.par_width >>= 1;
+ job->anamorphic.par_height >>= 1;
+ }
+ }
+ }
+
+ /* Keep width and height within these boundaries,
+ but ignore for anamorphic. For "loose" anamorphic encodes,
+ this stuff is covered in the pixel_ratio section above. */
+ if ( job->maxHeight && ( job->height > job->maxHeight ) && ( !job->anamorphic.mode ) )
+ {
+ job->height = job->maxHeight;
+ hb_fix_aspect( job, HB_KEEP_HEIGHT );
+ hb_log( "Height out of bounds, scaling down to %i", job->maxHeight );
+ hb_log( "New dimensions %i * %i", job->width, job->height );
+ }
+ if ( job->maxWidth && ( job->width > job->maxWidth ) && ( !job->anamorphic.mode ) )
+ {
+ job->width = job->maxWidth;
+ hb_fix_aspect( job, HB_KEEP_WIDTH );
+ hb_log( "Width out of bounds, scaling down to %i", job->maxWidth );
+ hb_log( "New dimensions %i * %i", job->width, job->height );
+ }
+
+ if( job->mux & HB_MUX_AVI )
+ {
+ // The concept of variable frame rate video was a bit too advanced
+ // for Microsoft so AVI doesn't support it. Since almost all dvd
+ // video is VFR we have to convert it to constant frame rate to
+ // put it in an AVI container. So duplicate, drop and
+ // otherwise trash video frames to appease the gods of Redmond.
+ job->cfr = 1;
+ }
+
+ if ( job->cfr == 0 )
+ {
+ /* Ensure we're using "Same as source" FPS */
+ job->vrate_base = title->rate_base;
+ }
+
+ job->fifo_mpeg2 = hb_fifo_init( FIFO_LARGE, FIFO_LARGE_WAKE );
+ job->fifo_raw = hb_fifo_init( FIFO_SMALL, FIFO_SMALL_WAKE );
+ job->fifo_sync = hb_fifo_init( FIFO_SMALL, FIFO_SMALL_WAKE );
+ job->fifo_render = hb_fifo_init( FIFO_SMALL, FIFO_SMALL_WAKE );
+ job->fifo_mpeg4 = hb_fifo_init( FIFO_LARGE, FIFO_LARGE_WAKE );
+
+ /*
+ * Audio fifos must be initialized before sync
+ */
+ if( !job->indepth_scan )
+ {
+ // if we are doing passthru, and the input codec is not the same as the output
+ // codec, then remove this audio from the job. If we're not doing passthru and
+ // the input codec is the 'internal' ffmpeg codec, make sure that only one
+ // audio references that audio stream since the codec context is specific to
+ // the audio id & multiple copies of the same stream will garble the audio
+ // or cause aborts.
+ uint8_t aud_id_uses[MAX_STREAMS];
+ memset( aud_id_uses, 0, sizeof(aud_id_uses) );