OSDN Git Service

57809d7e2468a5d200b589c2f96409139e1ce915
[handbrake-jp/handbrake-jp-git.git] / libhb / sync.c
1 /* $Id: sync.c,v 1.38 2005/04/14 21:57:58 titer Exp $
2
3    This file is part of the HandBrake source code.
4    Homepage: <http://handbrake.fr/>.
5    It may be used under the terms of the GNU General Public License. */
6
7 #include "hb.h"
8 #include "hbffmpeg.h"
9 #include <stdio.h>
10 #include "samplerate.h"
11
12 #ifdef INT64_MIN
13 #undef INT64_MIN /* Because it isn't defined correctly in Zeta */
14 #endif
15 #define INT64_MIN (-9223372036854775807LL-1)
16
17 #define AC3_SAMPLES_PER_FRAME 1536
18
19 typedef struct
20 {
21     hb_lock_t * mutex;
22     int         ref;        /* Reference count to tell us when it's unused */
23     int         count_frames;
24     int64_t     audio_passthru_slip;
25     int64_t     video_pts_slip;
26     int64_t     pts_offset;
27
28     /* Frame based point-to-point support */
29     int64_t     audio_pts_thresh;
30     int         start_found;
31     hb_cond_t * next_frame;
32     int         pts_count;
33     int64_t   * first_pts;
34 } hb_sync_common_t;
35
36 typedef struct
37 {
38     int          index;
39     int64_t      next_start;    /* start time of next output frame */
40     int64_t      next_pts;     /* start time of next input frame */
41     int64_t      first_drop;   /* PTS of first 'went backwards' frame dropped */
42     int          drop_count;   /* count of 'time went backwards' drops */
43
44     /* Raw */
45     SRC_STATE  * state;
46     SRC_DATA     data;
47
48     /* AC-3 */
49     int          ac3_size;
50     uint8_t    * ac3_buf;
51 } hb_sync_audio_t;
52
53 typedef struct
54 {
55     /* Video */
56     int        first_frame;
57     int64_t    pts_skip;
58     int64_t    next_start;    /* start time of next output frame */
59     int64_t    next_pts;      /* start time of next input frame */
60     int64_t    first_drop;    /* PTS of first 'went backwards' frame dropped */
61     int        drop_count;    /* count of 'time went backwards' drops */
62     int        drops;         /* frames dropped to make a cbr video stream */
63     int        dups;          /* frames duplicated to make a cbr video stream */
64     int        video_sequence;
65     int        count_frames_max;
66     int        chap_mark;     /* to propagate chapter mark across a drop */
67     hb_buffer_t * cur;        /* The next picture to process */
68
69     /* Statistics */
70     uint64_t   st_counts[4];
71     uint64_t   st_dates[4];
72     uint64_t   st_first;
73 } hb_sync_video_t;
74
75 struct hb_work_private_s
76 {
77     hb_job_t * job;
78     hb_sync_common_t * common;
79     union
80     {
81         hb_sync_video_t video;
82         hb_sync_audio_t audio;
83     } type;
84 };
85
86 /***********************************************************************
87  * Local prototypes
88  **********************************************************************/
89 static void getPtsOffset( hb_work_object_t * w );
90 static int  checkPtsOffset( hb_work_object_t * w );
91 static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i );
92 static void InsertSilence( hb_work_object_t * w, int64_t d );
93 static void UpdateState( hb_work_object_t * w );
94 static void UpdateSearchState( hb_work_object_t * w, int64_t start );
95 static hb_buffer_t * OutputAudioFrame( hb_audio_t *audio, hb_buffer_t *buf,
96                                        hb_sync_audio_t *sync );
97
98 /***********************************************************************
99  * hb_work_sync_init
100  ***********************************************************************
101  * Initialize the work object
102  **********************************************************************/
103 hb_work_object_t * hb_sync_init( hb_job_t * job )
104 {
105     hb_title_t        * title = job->title;
106     hb_chapter_t      * chapter;
107     int                 i;
108     uint64_t            duration;
109     hb_work_private_t * pv;
110     hb_sync_video_t   * sync;
111     hb_work_object_t  * w;
112     hb_work_object_t  * ret = NULL;
113
114     pv = calloc( 1, sizeof( hb_work_private_t ) );
115     sync = &pv->type.video;
116     pv->common = calloc( 1, sizeof( hb_sync_common_t ) );
117     pv->common->ref++;
118     pv->common->mutex = hb_lock_init();
119     pv->common->audio_pts_thresh = -1;
120     pv->common->next_frame = hb_cond_init();
121     pv->common->pts_count = 1;
122     if ( job->frame_to_start || job->pts_to_start )
123     {
124         pv->common->start_found = 0;
125     }
126     else
127     {
128         pv->common->start_found = 1;
129     }
130
131     ret = w = hb_get_work( WORK_SYNC_VIDEO );
132     w->private_data = pv;
133     w->fifo_in = job->fifo_raw;
134     w->fifo_out = job->fifo_sync;
135
136     pv->job            = job;
137     pv->common->pts_offset   = INT64_MIN;
138     sync->first_frame = 1;
139
140     if( job->pass == 2 )
141     {
142         /* We already have an accurate frame count from pass 1 */
143         hb_interjob_t * interjob = hb_interjob_get( job->h );
144         sync->count_frames_max = interjob->frame_count;
145     }
146     else
147     {
148         /* Calculate how many video frames we are expecting */
149         if ( job->pts_to_stop )
150         {
151             duration = job->pts_to_stop + 90000;
152         }
153         else if( job->frame_to_stop )
154         {
155             /* Set the duration to a rough estimate */
156             duration = ( job->frame_to_stop / ( title->rate / title->rate_base ) ) * 90000;
157         }
158         else
159         {
160             duration = 0;
161             for( i = job->chapter_start; i <= job->chapter_end; i++ )
162             {
163                 chapter   = hb_list_item( title->list_chapter, i - 1 );
164                 duration += chapter->duration;
165             }
166             duration += 90000;
167             /* 1 second safety so we're sure we won't miss anything */
168         }
169         sync->count_frames_max = duration * title->rate / title->rate_base / 90000;
170     }
171
172     hb_log( "sync: expecting %d video frames", sync->count_frames_max );
173
174     /* Initialize libsamplerate for every audio track we have */
175     if ( ! job->indepth_scan )
176     {
177         for( i = 0; i < hb_list_count( title->list_audio ); i++ )
178         {
179             InitAudio( job, pv->common, i );
180         }
181     }
182     pv->common->first_pts = malloc( sizeof(int64_t) * pv->common->pts_count );
183     for ( i = 0; i < pv->common->pts_count; i++ )
184         pv->common->first_pts[i] = INT64_MAX;
185
186     return ret;
187 }
188
189 /***********************************************************************
190  * Close Video
191  ***********************************************************************
192  *
193  **********************************************************************/
194 void syncVideoClose( hb_work_object_t * w )
195 {
196     hb_work_private_t * pv = w->private_data;
197     hb_job_t          * job   = pv->job;
198     hb_sync_video_t   * sync = &pv->type.video;
199
200     // Wake up audio sync if it's still waiting on condition.
201     pv->common->pts_offset = 0;
202     pv->common->start_found = 1;
203     hb_cond_broadcast( pv->common->next_frame );
204
205     if( sync->cur )
206     {
207         hb_buffer_close( &sync->cur );
208     }
209
210     hb_log( "sync: got %d frames, %d expected",
211             pv->common->count_frames, sync->count_frames_max );
212
213     /* save data for second pass */
214     if( job->pass == 1 )
215     {
216         /* Preserve frame count for better accuracy in pass 2 */
217         hb_interjob_t * interjob = hb_interjob_get( job->h );
218         interjob->frame_count = pv->common->count_frames;
219         interjob->last_job = job->sequence_id;
220         interjob->total_time = sync->next_start;
221     }
222
223     if (sync->drops || sync->dups )
224     {
225         hb_log( "sync: %d frames dropped, %d duplicated", 
226                 sync->drops, sync->dups );
227     }
228
229     hb_lock( pv->common->mutex );
230     if ( --pv->common->ref == 0 )
231     {
232         hb_unlock( pv->common->mutex );
233         hb_lock_close( &pv->common->mutex );
234         free( pv->common );
235     }
236     else
237     {
238         hb_unlock( pv->common->mutex );
239     }
240
241     free( pv );
242     w->private_data = NULL;
243 }
244
245 /***********************************************************************
246  * syncVideoWork
247  ***********************************************************************
248  *
249  **********************************************************************/
250 static hb_buffer_t * copy_subtitle( hb_buffer_t * src );
251
252 int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
253               hb_buffer_t ** buf_out )
254 {
255     hb_buffer_t * cur, * next, * sub = NULL;
256     hb_work_private_t * pv = w->private_data;
257     hb_job_t          * job = pv->job;
258     hb_subtitle_t     * subtitle;
259     hb_sync_video_t   * sync = &pv->type.video;
260     int i;
261
262     *buf_out = NULL;
263     next = *buf_in;
264     *buf_in = NULL;
265
266     /* Wait for start of point-to-point encoding */
267     if( !pv->common->start_found )
268     {
269         hb_sync_video_t   * sync = &pv->type.video;
270
271         if( next->size == 0 )
272         {
273             *buf_out = next;
274             pv->common->start_found = 1;
275             hb_cond_broadcast( pv->common->next_frame );
276
277             /*
278              * Push through any subtitle EOFs in case they 
279              * were not synced through.
280              */
281             for( i = 0; i < hb_list_count( job->list_subtitle ); i++)
282             {
283                 subtitle = hb_list_item( job->list_subtitle, i );
284                 if( subtitle->config.dest == PASSTHRUSUB )
285                 {
286                     if( subtitle->source == VOBSUB ) 
287                         hb_fifo_push( subtitle->fifo_sync, hb_buffer_init( 0 ) );
288                     else
289                         hb_fifo_push( subtitle->fifo_out, hb_buffer_init( 0 ) );
290                 }
291             }
292             return HB_WORK_DONE;
293         }
294         if ( pv->common->count_frames < job->frame_to_start ||
295              next->start < job->pts_to_start )
296         {
297             // Flush any subtitles that have pts prior to the
298             // current frame
299             for( i = 0; i < hb_list_count( job->list_subtitle ); i++)
300             {
301                 subtitle = hb_list_item( job->list_subtitle, i );
302                 while( ( sub = hb_fifo_see( subtitle->fifo_raw ) ) )
303                 {
304                     if ( sub->start > next->start )
305                         break;
306                     sub = hb_fifo_get( subtitle->fifo_raw );
307                     hb_buffer_close( &sub );
308                 }
309             }
310             hb_lock( pv->common->mutex );
311             // Tell the audio threads what must be dropped
312             pv->common->audio_pts_thresh = next->start;
313             hb_cond_broadcast( pv->common->next_frame );
314             hb_unlock( pv->common->mutex );
315
316             UpdateSearchState( w, next->start );
317             hb_buffer_close( &next );
318
319             return HB_WORK_OK;
320         }
321         hb_lock( pv->common->mutex );
322         pv->common->start_found = 1;
323         pv->common->count_frames = 0;
324         hb_cond_broadcast( pv->common->next_frame );
325         hb_unlock( pv->common->mutex );
326         sync->st_first = 0;
327     }
328
329     /* Wait till we can determine the initial pts of all streams */
330     if( next->size != 0 && pv->common->pts_offset == INT64_MIN )
331     {
332         pv->common->first_pts[0] = next->start;
333         hb_lock( pv->common->mutex );
334         while( pv->common->pts_offset == INT64_MIN )
335         {
336             // Full fifos will make us wait forever, so get the
337             // pts offset from the available streams if full
338             if ( hb_fifo_is_full( job->fifo_raw ) )
339             {
340                 getPtsOffset( w );
341                 hb_cond_broadcast( pv->common->next_frame );
342             }
343             else if ( checkPtsOffset( w ) )
344                 hb_cond_broadcast( pv->common->next_frame );
345             else
346                 hb_cond_timedwait( pv->common->next_frame, pv->common->mutex, 200 );
347         }
348         hb_unlock( pv->common->mutex );
349     }
350
351     if( !sync->cur )
352     {
353         sync->cur = next;
354         if( sync->cur->size == 0 )
355         {
356             /* we got an end-of-stream as our first video packet? 
357              * Feed it downstream & signal that we're done. 
358              */
359             *buf_out = hb_buffer_init( 0 );
360
361             pv->common->start_found = 1;
362             hb_cond_broadcast( pv->common->next_frame );
363
364             /*
365              * Push through any subtitle EOFs in case they 
366              * were not synced through.
367              */
368             for( i = 0; i < hb_list_count( job->list_subtitle ); i++)
369             {
370                 subtitle = hb_list_item( job->list_subtitle, i );
371                 if( subtitle->config.dest == PASSTHRUSUB )
372                 {
373                     if( subtitle->source == VOBSUB ) 
374                         hb_fifo_push( subtitle->fifo_sync, hb_buffer_init( 0 ) );
375                     else
376                         hb_fifo_push( subtitle->fifo_out, hb_buffer_init( 0 ) );
377                 }
378             }
379             return HB_WORK_DONE;
380         }
381         return HB_WORK_OK;
382     }
383     cur = sync->cur;
384     /* At this point we have a frame to process. Let's check
385         1) if we will be able to push into the fifo ahead
386         2) if the next frame is there already, since we need it to
387            compute the duration of the current frame*/
388     if( next->size == 0 )
389     {
390         hb_buffer_close( &next );
391
392         cur->start = sync->next_start;
393         cur->stop = cur->start + 90000. / ((double)job->vrate / (double)job->vrate_base);
394
395         /* Make sure last frame is reflected in frame count */
396         pv->common->count_frames++;
397
398         /* Push the frame to the renderer */
399         hb_fifo_push( job->fifo_sync, cur );
400         sync->cur = NULL;
401
402         /* we got an end-of-stream. Feed it downstream & signal that
403          * we're done. Note that this means we drop the final frame of
404          * video (we don't know its duration). On DVDs the final frame
405          * is often strange and dropping it seems to be a good idea. */
406         *buf_out = hb_buffer_init( 0 );
407
408         /*
409          * Push through any subtitle EOFs in case they were not synced through.
410          */
411         for( i = 0; i < hb_list_count( job->list_subtitle ); i++)
412         {
413             subtitle = hb_list_item( job->list_subtitle, i );
414             if( subtitle->config.dest == PASSTHRUSUB )
415             {
416                 if( subtitle->source == VOBSUB ) 
417                     hb_fifo_push( subtitle->fifo_sync, hb_buffer_init( 0 ) );
418                 else
419                     hb_fifo_push( subtitle->fifo_out, hb_buffer_init( 0 ) );
420             }
421         }
422         pv->common->start_found = 1;
423         hb_cond_broadcast( pv->common->next_frame );
424         return HB_WORK_DONE;
425     }
426
427     /* Check for end of point-to-point frame encoding */
428     if( job->frame_to_stop && pv->common->count_frames > job->frame_to_stop )
429     {
430         // Drop an empty buffer into our output to ensure that things
431         // get flushed all the way out.
432         hb_buffer_close( &sync->cur );
433         hb_buffer_close( &next );
434         *buf_out = hb_buffer_init( 0 );
435         hb_log( "sync: reached %d frames, exiting early",
436                 pv->common->count_frames );
437
438         /*
439          * Push through any subtitle EOFs in case they were not synced through.
440          */
441         for( i = 0; i < hb_list_count( job->list_subtitle ); i++)
442         {
443             subtitle = hb_list_item( job->list_subtitle, i );
444             if( subtitle->config.dest == PASSTHRUSUB )
445             {
446                 if( subtitle->source == VOBSUB ) 
447                     hb_fifo_push( subtitle->fifo_sync, hb_buffer_init( 0 ) );
448                 else
449                     hb_fifo_push( subtitle->fifo_out, hb_buffer_init( 0 ) );
450             }
451         }
452         return HB_WORK_DONE;
453     }
454
455     /* Check for end of point-to-point pts encoding */
456     if( job->pts_to_stop && sync->next_start >= job->pts_to_stop )
457     {
458         // Drop an empty buffer into our output to ensure that things
459         // get flushed all the way out.
460         hb_log( "sync: reached pts %"PRId64", exiting early",
461                 sync->cur->start );
462         hb_buffer_close( &sync->cur );
463         hb_buffer_close( &next );
464         *buf_out = hb_buffer_init( 0 );
465
466         /*
467          * Push through any subtitle EOFs in case they were not synced through.
468          */
469         for( i = 0; i < hb_list_count( job->list_subtitle ); i++)
470         {
471             subtitle = hb_list_item( job->list_subtitle, i );
472             if( subtitle->config.dest == PASSTHRUSUB )
473             {
474                 if( subtitle->source == VOBSUB ) 
475                     hb_fifo_push( subtitle->fifo_sync, hb_buffer_init( 0 ) );
476                 else
477                     hb_fifo_push( subtitle->fifo_out, hb_buffer_init( 0 ) );
478             }
479         }
480         return HB_WORK_DONE;
481     }
482
483     if( sync->first_frame )
484     {
485         /* This is our first frame */
486         if ( cur->start > pv->common->pts_offset )
487         {
488             /*
489              * The first pts from a dvd should always be zero but
490              * can be non-zero with a transport or program stream since
491              * we're not guaranteed to start on an IDR frame. If we get
492              * a non-zero initial PTS extend its duration so it behaves
493              * as if it started at zero so that our audio timing will
494              * be in sync.
495              */
496             hb_log( "sync: first pts is %"PRId64, cur->start );
497             cur->start = pv->common->pts_offset;
498         }
499         sync->first_frame = 0;
500     }
501
502     /*
503      * since the first frame is always 0 and the upstream reader code
504      * is taking care of adjusting for pts discontinuities, we just have
505      * to deal with the next frame's start being in the past. This can
506      * happen when the PTS is adjusted after data loss but video frame
507      * reordering causes some frames with the old clock to appear after
508      * the clock change. This creates frames that overlap in time which
509      * looks to us like time going backward. The downstream muxing code
510      * can deal with overlaps of up to a frame time but anything larger
511      * we handle by dropping frames here.
512      */
513     hb_lock( pv->common->mutex );
514     if ( (int64_t)( next->start - pv->common->video_pts_slip - cur->start ) <= 0 )
515     {
516         if ( sync->first_drop == 0 )
517         {
518             sync->first_drop = next->start;
519         }
520         ++sync->drop_count;
521         if (next->start - cur->start > 0)
522         {
523             sync->pts_skip += next->start - cur->start;
524             pv->common->video_pts_slip -= next->start - cur->start;
525         }
526         hb_unlock( pv->common->mutex );
527         if ( next->new_chap )
528         {
529             // don't drop a chapter mark when we drop the buffer
530             sync->chap_mark = next->new_chap;
531         }
532         hb_buffer_close( &next );
533         return HB_WORK_OK;
534     }
535     hb_unlock( pv->common->mutex );
536     if ( sync->first_drop )
537     {
538         hb_log( "sync: video time didn't advance - dropped %d frames "
539                 "(delta %d ms, current %"PRId64", next %"PRId64", dur %d)",
540                 sync->drop_count, (int)( cur->start - sync->first_drop ) / 90,
541                 cur->start, next->start, (int)( next->start - cur->start ) );
542         sync->first_drop = 0;
543         sync->drop_count = 0;
544     }
545
546     /*
547      * Track the video sequence number localy so that we can sync the audio
548      * to it using the sequence number as well as the PTS.
549      */
550     sync->video_sequence = cur->sequence;
551
552     /*
553      * Look for a subtitle for this frame.
554      *
555      * If found then it will be tagged onto a video buffer of the correct time and 
556      * sent in to the render pipeline. This only needs to be done for VOBSUBs which
557      * get rendered, other types of subtitles can just sit in their raw_queue until
558      * delt with at muxing.
559      */
560     for( i = 0; i < hb_list_count( job->list_subtitle ); i++)
561     {
562         subtitle = hb_list_item( job->list_subtitle, i );
563
564         /*
565          * Rewrite timestamps on subtitles that need it (on raw queue).
566          */
567         // NOTE: It's probably fine to use this logic for passthru VOBSUBs as well,
568         //       but I am currently preserving backwards compatibility with the old
569         //       VOBSUB behavior, which uses the more complex logic following this if-statement.
570         if( subtitle->config.dest == PASSTHRUSUB && subtitle->source != VOBSUB )
571         {
572             /*
573              * Rewrite timestamps on subtitles that came from Closed Captions
574              * since they are using the MPEG2 timestamps.
575              */
576             while( ( sub = hb_fifo_see( subtitle->fifo_raw ) ) )
577             {
578                 /*
579                  * Rewrite the timestamps as and when the video
580                  * (cur->start) reaches the same timestamp as a
581                  * closed caption (sub->start).
582                  *
583                  * What about discontinuity boundaries - not delt
584                  * with here - Van?
585                  *
586                  * Bypass the sync fifo altogether.
587                  */
588                 if( sub->size <= 0 )
589                 {
590                     sub = hb_fifo_get( subtitle->fifo_raw );
591                     hb_fifo_push( subtitle->fifo_out, sub );
592                     sub = NULL;
593                     break;
594                 } else {
595                     /*
596                      * Sync the subtitles to the incoming video, and use
597                      * the matching converted video timestamp.
598                      *
599                      * Note that it doesn't appear that we need to convert 
600                      * timestamps, I guess that they were already correct,
601                      * so just push them through for rendering.
602                      *
603                      */
604                     if( sub->start < cur->start )
605                     {
606                         sub = hb_fifo_get( subtitle->fifo_raw );
607                         hb_fifo_push( subtitle->fifo_out, sub );
608                     } else {
609                         sub = NULL;
610                         break;
611                     }
612                 }
613             }
614             
615             continue;
616         }
617
618         // For rendered subtitles (and, for backward compatibility, passthru VOBSUBs),
619         // delay pushing subtitle packets through the pipeline until the video catches up
620         if( subtitle->config.dest == RENDERSUB || subtitle->source == VOBSUB ) 
621         {
622             hb_buffer_t * sub2;
623             while( ( sub = hb_fifo_see( subtitle->fifo_raw ) ) )
624             {
625                 if( sub->size == 0 )
626                 {
627                     /*
628                      * EOF, pass it through immediately.
629                      */
630                     break;
631                 }
632
633                 /* If two subtitles overlap, make the first one stop
634                    when the second one starts */
635                 sub2 = hb_fifo_see2( subtitle->fifo_raw );
636                 if( sub2 && sub->stop > sub2->start )
637                 {
638                     sub->stop = sub2->start;
639                 }
640                 
641                 // hb_log("0x%x: video seq: %"PRId64" subtitle sequence: %"PRId64,
642                 //       sub, cur->sequence, sub->sequence);
643                 
644                 if( sub->sequence > cur->sequence )
645                 {
646                     /*
647                      * The video is behind where we are, so wait until
648                      * it catches up to the same reader point on the
649                      * DVD. Then our PTS should be in the same region
650                      * as the video.
651                      */
652                     sub = NULL;
653                     break;
654                 }
655                 
656                 if( sub->stop > cur->start ) {
657                     /*
658                      * The stop time is in the future, so fall through
659                      * and we'll deal with it in the next block of
660                      * code.
661                      */
662
663                     /*
664                      * There is a valid subtitle, is it time to display it?
665                      */
666                     if( sub->stop > sub->start)
667                     {
668                         /*
669                          * Normal subtitle which ends after it starts, 
670                          * check to see that the current video is between 
671                          * the start and end.
672                          */
673                         if( cur->start > sub->start &&
674                             cur->start < sub->stop )
675                         {
676                             /*
677                             * We should be playing this, so leave the
678                             * subtitle in place.
679                             *
680                             * fall through to display
681                             */
682                             if( ( sub->stop - sub->start ) < ( 2 * 90000 ) )
683                             {
684                                 /*
685                                  * Subtitle is on for less than three 
686                                  * seconds, extend the time that it is 
687                                  * displayed to make it easier to read. 
688                                  * Make it 2 seconds or until the next
689                                  * subtitle is displayed.
690                                  *
691                                  * This is in response to Indochine which 
692                                  * only displays subs for 1 second - 
693                                  * too fast to read.
694                                  */
695                                 sub->stop = sub->start + ( 2 * 90000 );
696                             
697                                 sub2 = hb_fifo_see2( subtitle->fifo_raw );
698                             
699                                 if( sub2 && sub->stop > sub2->start )
700                                 {
701                                     sub->stop = sub2->start;
702                                 }
703                             }
704                         }
705                         else
706                         {
707                             /*
708                              * Defer until the play point is within 
709                              * the subtitle
710                              */
711                             sub = NULL;
712                         }
713                     }
714                     else
715                     {
716                         /*
717                          * The end of the subtitle is less than the start, 
718                          * this is a sign of a PTS discontinuity.
719                          */
720                         if( sub->start > cur->start )
721                         {
722                             /*
723                              * we haven't reached the start time yet, or
724                              * we have jumped backwards after having
725                              * already started this subtitle.
726                              */
727                             if( cur->start < sub->stop )
728                             {
729                                 /*
730                                  * We have jumped backwards and so should
731                                  * continue displaying this subtitle.
732                                  *
733                                  * fall through to display.
734                                  */
735                             }
736                             else
737                             {
738                                 /*
739                                  * Defer until the play point is 
740                                  * within the subtitle
741                                  */
742                                 sub = NULL;
743                             }
744                         } else {
745                             /*
746                             * Play this subtitle as the start is 
747                             * greater than our video point.
748                             *
749                             * fall through to display/
750                             */
751                         }
752                     }
753                         break;
754                 }
755                 else
756                 {
757                     
758                     /*
759                      * The subtitle is older than this picture, trash it
760                      */
761                     sub = hb_fifo_get( subtitle->fifo_raw );
762                     hb_buffer_close( &sub );
763                 }
764             }
765             
766             /* If we have a subtitle for this picture, copy it */
767             if( sub )
768             {
769                 if( sub->size > 0 )
770                 {
771                     if( subtitle->config.dest == RENDERSUB )
772                     {
773                         // Only allow one subtitle to be showing at once; ignore others
774                         if ( cur->sub == NULL )
775                         {
776                             /*
777                              * Tack onto the video buffer for rendering
778                              */
779                             /* FIXME: we should avoid this memcpy */
780                             cur->sub = copy_subtitle( sub );
781                             
782                             // Leave the subtitle on the raw queue
783                             // (until it no longer needs to be displayed)
784                         }
785                     } else {
786                         /*
787                          * Pass-Through, pop it off of the raw queue, 
788                          */
789                         sub = hb_fifo_get( subtitle->fifo_raw );
790                         hb_fifo_push( subtitle->fifo_sync, sub );
791                     }
792                 } else {
793                     /*
794                     * EOF - consume for rendered, else pass through
795                     */
796                     if( subtitle->config.dest == RENDERSUB )
797                     {
798                         sub = hb_fifo_get( subtitle->fifo_raw );
799                         hb_buffer_close( &sub );
800                     } else {
801                         sub = hb_fifo_get( subtitle->fifo_raw );
802                         hb_fifo_push( subtitle->fifo_sync, sub );
803                     }
804                 }
805             }
806         }
807     } // end subtitles
808
809     /*
810      * Adjust the pts of the current frame so that it's contiguous
811      * with the previous frame. The start time of the current frame
812      * has to be the end time of the previous frame and the stop
813      * time has to be the start of the next frame.  We don't
814      * make any adjustments to the source timestamps other than removing
815      * the clock offsets (which also removes pts discontinuities).
816      * This means we automatically encode at the source's frame rate.
817      * MP2 uses an implicit duration (frames end when the next frame
818      * starts) but more advanced containers like MP4 use an explicit
819      * duration. Since we're looking ahead one frame we set the
820      * explicit stop time from the start time of the next frame.
821      */
822     *buf_out = cur;
823     sync->cur = cur = next;
824     cur->sub = NULL;
825     sync->next_pts = cur->start;
826     int64_t duration = cur->start - sync->pts_skip - (*buf_out)->start;
827     sync->pts_skip = 0;
828     if ( duration <= 0 )
829     {
830         hb_log( "sync: invalid video duration %"PRId64", start %"PRId64", next %"PRId64"",
831                 duration, (*buf_out)->start, next->start );
832     }
833
834     (*buf_out)->start = sync->next_start;
835     sync->next_start += duration;
836     (*buf_out)->stop = sync->next_start;
837
838     if ( sync->chap_mark )
839     {
840         // we have a pending chapter mark from a recent drop - put it on this
841         // buffer (this may make it one frame late but we can't do any better).
842         (*buf_out)->new_chap = sync->chap_mark;
843         sync->chap_mark = 0;
844     }
845
846     /* Update UI */
847     UpdateState( w );
848
849     return HB_WORK_OK;
850 }
851
852 static hb_buffer_t * copy_subtitle( hb_buffer_t * src_list )
853 {
854     hb_buffer_t * dst_list = NULL;
855     
856     hb_buffer_t * src;
857     hb_buffer_t * dst;
858     hb_buffer_t ** dst_ptr = &dst_list;
859     for ( src = src_list, dst_ptr = &dst_list;
860           src;
861           src = src->next_subpicture, dst_ptr = &dst->next_subpicture )
862     {
863         (*dst_ptr)  = hb_buffer_init( src->size );
864         dst         = (*dst_ptr); 
865         dst->x      = src->x;
866         dst->y      = src->y;
867         dst->width  = src->width;
868         dst->height = src->height;
869         memcpy( dst->data, src->data, src->size );
870     }
871     
872     return dst_list;
873 }
874
875 // sync*Init does nothing because sync has a special initializer
876 // that takes care of initializing video and all audio tracks
877 int syncVideoInit( hb_work_object_t * w, hb_job_t * job)
878 {
879     return 0;
880 }
881
882 hb_work_object_t hb_sync_video =
883 {
884     WORK_SYNC_VIDEO,
885     "Video Synchronization",
886     syncVideoInit,
887     syncVideoWork,
888     syncVideoClose
889 };
890
891 /***********************************************************************
892  * Close Audio
893  ***********************************************************************
894  *
895  **********************************************************************/
896 void syncAudioClose( hb_work_object_t * w )
897 {
898     hb_work_private_t * pv    = w->private_data;
899     hb_sync_audio_t   * sync  = &pv->type.audio;
900
901     if( w->audio->config.out.codec == HB_ACODEC_AC3_PASS )
902     {
903         free( sync->ac3_buf );
904     }
905     else
906     {
907         src_delete( sync->state );
908     }
909
910     hb_lock( pv->common->mutex );
911     if ( --pv->common->ref == 0 )
912     {
913         hb_unlock( pv->common->mutex );
914         hb_lock_close( &pv->common->mutex );
915         free( pv->common );
916     }
917     else
918     {
919         hb_unlock( pv->common->mutex );
920     }
921
922     free( pv );
923     w->private_data = NULL;
924 }
925
926 int syncAudioInit( hb_work_object_t * w, hb_job_t * job)
927 {
928     return 0;
929 }
930
931 /***********************************************************************
932  * SyncAudio
933  ***********************************************************************
934  *
935  **********************************************************************/
936 static int syncAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
937                        hb_buffer_t ** buf_out )
938 {
939     hb_work_private_t * pv = w->private_data;
940     hb_job_t        * job = pv->job;
941     hb_sync_audio_t * sync = &pv->type.audio;
942     hb_buffer_t     * buf;
943     int64_t start;
944
945     *buf_out = NULL;
946     buf = *buf_in;
947     *buf_in = NULL;
948     /* if the next buffer is an eof send it downstream */
949     if ( buf->size <= 0 )
950     {
951         hb_buffer_close( &buf );
952         *buf_out = hb_buffer_init( 0 );
953         return HB_WORK_DONE;
954     }
955
956     /* Wait for start frame if doing point-to-point */
957     hb_lock( pv->common->mutex );
958     while ( !pv->common->start_found )
959     {
960         if ( pv->common->audio_pts_thresh < 0 )
961         {
962             // I would initialize this in hb_sync_init, but 
963             // job->pts_to_start can be modified by reader 
964             // after hb_sync_init is called.
965             pv->common->audio_pts_thresh = job->pts_to_start;
966         }
967         if ( buf->start < pv->common->audio_pts_thresh )
968         {
969             hb_buffer_close( &buf );
970             hb_unlock( pv->common->mutex );
971             return HB_WORK_OK;
972         }
973         while ( !pv->common->start_found && 
974                 buf->start >= pv->common->audio_pts_thresh )
975         {
976             hb_cond_timedwait( pv->common->next_frame, pv->common->mutex, 200 );
977         }
978     }
979     if ( buf->start < pv->common->audio_pts_thresh )
980     {
981         hb_buffer_close( &buf );
982         hb_unlock( pv->common->mutex );
983         return HB_WORK_OK;
984     }
985     hb_unlock( pv->common->mutex );
986
987     /* Wait till we can determine the initial pts of all streams */
988     if( pv->common->pts_offset == INT64_MIN )
989     {
990         pv->common->first_pts[sync->index+1] = buf->start;
991         hb_lock( pv->common->mutex );
992         while( pv->common->pts_offset == INT64_MIN )
993         {
994             // Full fifos will make us wait forever, so get the
995             // pts offset from the available streams if full
996             if (hb_fifo_is_full(w->fifo_in))
997             {
998                 getPtsOffset( w );
999                 hb_cond_broadcast( pv->common->next_frame );
1000             }
1001             else if ( checkPtsOffset( w ) )
1002                 hb_cond_broadcast( pv->common->next_frame );
1003             else
1004                 hb_cond_timedwait( pv->common->next_frame, pv->common->mutex, 200 );
1005         }
1006         hb_unlock( pv->common->mutex );
1007     }
1008
1009     if( job->frame_to_stop && pv->common->count_frames >= job->frame_to_stop )
1010     {
1011         hb_buffer_close( &buf );
1012         *buf_out = hb_buffer_init( 0 );
1013         return HB_WORK_DONE;
1014     }
1015
1016     if( job->pts_to_stop && sync->next_start >= job->pts_to_stop )
1017     {
1018         hb_buffer_close( &buf );
1019         *buf_out = hb_buffer_init( 0 );
1020         return HB_WORK_DONE;
1021     }
1022
1023     hb_lock( pv->common->mutex );
1024     start = buf->start - pv->common->audio_passthru_slip;
1025     hb_unlock( pv->common->mutex );
1026     if ( (int64_t)( start - sync->next_pts ) < 0 )
1027     {
1028         // audio time went backwards.
1029         // If our output clock is more than a half frame ahead of the
1030         // input clock drop this frame to move closer to sync.
1031         // Otherwise drop frames until the input clock matches the output clock.
1032         if ( sync->first_drop || sync->next_start - start > 90*15 )
1033         {
1034             // Discard data that's in the past.
1035             if ( sync->first_drop == 0 )
1036             {
1037                 sync->first_drop = sync->next_pts;
1038             }
1039             ++sync->drop_count;
1040             hb_buffer_close( &buf );
1041             return HB_WORK_OK;
1042         }
1043         sync->next_pts = start;
1044     }
1045     if ( sync->first_drop )
1046     {
1047         // we were dropping old data but input buf time is now current
1048         hb_log( "sync: audio %d time went backwards %d ms, dropped %d frames "
1049                 "(next %"PRId64", current %"PRId64")", w->audio->id,
1050                 (int)( sync->next_pts - sync->first_drop ) / 90,
1051                 sync->drop_count, sync->first_drop, sync->next_pts );
1052         sync->first_drop = 0;
1053         sync->drop_count = 0;
1054         sync->next_pts = start;
1055     }
1056     if ( start - sync->next_pts >= (90 * 70) )
1057     {
1058         if ( start - sync->next_pts > (90000LL * 60) )
1059         {
1060             // there's a gap of more than a minute between the last
1061             // frame and this. assume we got a corrupted timestamp
1062             // and just drop the next buf.
1063             hb_log( "sync: %d minute time gap in audio %d - dropping buf"
1064                     "  start %"PRId64", next %"PRId64,
1065                     (int)((start - sync->next_pts) / (90000*60)),
1066                     w->audio->id, start, sync->next_pts );
1067             hb_buffer_close( &buf );
1068             return HB_WORK_OK;
1069         }
1070         /*
1071          * there's a gap of at least 70ms between the last
1072          * frame we processed & the next. Fill it with silence.
1073          * Or in the case of DCA, skip some frames from the
1074          * other streams.
1075          */
1076         if( w->audio->config.out.codec == HB_ACODEC_DCA_PASS )
1077         {
1078             hb_log( "sync: audio gap %d ms. Skipping frames. Audio %d"
1079                     "  start %"PRId64", next %"PRId64,
1080                     (int)((start - sync->next_pts) / 90),
1081                     w->audio->id, start, sync->next_pts );
1082             hb_lock( pv->common->mutex );
1083             pv->common->audio_passthru_slip += (start - sync->next_pts);
1084             pv->common->video_pts_slip += (start - sync->next_pts);
1085             hb_unlock( pv->common->mutex );
1086             *buf_out = buf;
1087             return HB_WORK_OK;
1088         }
1089         hb_log( "sync: adding %d ms of silence to audio %d"
1090                 "  start %"PRId64", next %"PRId64,
1091                 (int)((start - sync->next_pts) / 90),
1092                 w->audio->id, start, sync->next_pts );
1093         InsertSilence( w, start - sync->next_pts );
1094     }
1095
1096     /*
1097      * When we get here we've taken care of all the dups and gaps in the
1098      * audio stream and are ready to inject the next input frame into
1099      * the output stream.
1100      */
1101     *buf_out = OutputAudioFrame( w->audio, buf, sync );
1102     return HB_WORK_OK;
1103 }
1104
1105 hb_work_object_t hb_sync_audio =
1106 {
1107     WORK_SYNC_AUDIO,
1108     "AudioSynchronization",
1109     syncAudioInit,
1110     syncAudioWork,
1111     syncAudioClose
1112 };
1113
1114 static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i )
1115 {
1116     hb_work_object_t  * w;
1117     hb_work_private_t * pv;
1118     hb_title_t        * title = job->title;
1119     hb_sync_audio_t   * sync;
1120
1121     pv = calloc( 1, sizeof( hb_work_private_t ) );
1122     sync = &pv->type.audio;
1123     sync->index = i;
1124     pv->job    = job;
1125     pv->common = common;
1126     pv->common->ref++;
1127     pv->common->pts_count++;
1128
1129     w = hb_get_work( WORK_SYNC_AUDIO );
1130     w->private_data = pv;
1131     w->audio = hb_list_item( title->list_audio, i );
1132     w->fifo_in = w->audio->priv.fifo_raw;
1133
1134     if( w->audio->config.out.codec == HB_ACODEC_AC3_PASS ||
1135         w->audio->config.out.codec == HB_ACODEC_DCA_PASS )
1136     {
1137         w->fifo_out = w->audio->priv.fifo_out;
1138     }
1139     else
1140     {
1141         w->fifo_out = w->audio->priv.fifo_sync;
1142     }
1143
1144     if( w->audio->config.out.codec == HB_ACODEC_AC3_PASS )
1145     {
1146         /* Have a silent AC-3 frame ready in case we have to fill a
1147            gap */
1148         AVCodec        * codec;
1149         AVCodecContext * c;
1150         short          * zeros;
1151
1152         codec = avcodec_find_encoder( CODEC_ID_AC3 );
1153         c     = avcodec_alloc_context();
1154
1155         c->bit_rate    = w->audio->config.in.bitrate;
1156         c->sample_rate = w->audio->config.in.samplerate;
1157         c->channels    = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT( w->audio->config.in.channel_layout );
1158
1159         if( hb_avcodec_open( c, codec ) < 0 )
1160         {
1161             hb_log( "sync: avcodec_open failed" );
1162             return;
1163         }
1164
1165         zeros          = calloc( AC3_SAMPLES_PER_FRAME *
1166                                  sizeof( short ) * c->channels, 1 );
1167         sync->ac3_size = w->audio->config.in.bitrate * AC3_SAMPLES_PER_FRAME /
1168                              w->audio->config.in.samplerate / 8;
1169         sync->ac3_buf  = malloc( sync->ac3_size );
1170
1171         if( avcodec_encode_audio( c, sync->ac3_buf, sync->ac3_size,
1172                                   zeros ) != sync->ac3_size )
1173         {
1174             hb_log( "sync: avcodec_encode_audio failed" );
1175         }
1176
1177         free( zeros );
1178         hb_avcodec_close( c );
1179         av_free( c );
1180     }
1181     else
1182     {
1183         /* Initialize libsamplerate */
1184         int error;
1185         sync->state = src_new( SRC_SINC_MEDIUM_QUALITY, 
1186             HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(
1187                 w->audio->config.out.mixdown), &error );
1188         sync->data.end_of_input = 0;
1189     }
1190     hb_list_add( job->list_work, w );
1191 }
1192
1193 static hb_buffer_t * OutputAudioFrame( hb_audio_t *audio, hb_buffer_t *buf,
1194                                        hb_sync_audio_t *sync )
1195 {
1196     int64_t start = sync->next_start;
1197     int64_t duration = buf->stop - buf->start;
1198
1199     sync->next_pts += duration;
1200
1201     if( audio->config.in.samplerate == audio->config.out.samplerate ||
1202         audio->config.out.codec == HB_ACODEC_AC3_PASS ||
1203         audio->config.out.codec == HB_ACODEC_DCA_PASS )
1204     {
1205         /*
1206          * If we don't have to do sample rate conversion or this audio is 
1207          * pass-thru just send the input buffer downstream after adjusting
1208          * its timestamps to make the output stream continuous.
1209          */
1210     }
1211     else
1212     {
1213         /* Not pass-thru - do sample rate conversion */
1214         int count_in, count_out;
1215         hb_buffer_t * buf_raw = buf;
1216         int channel_count = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown) *
1217                             sizeof( float );
1218
1219         count_in  = buf_raw->size / channel_count;
1220         /*
1221          * When using stupid rates like 44.1 there will always be some
1222          * truncation error. E.g., a 1536 sample AC3 frame will turn into a
1223          * 1536*44.1/48.0 = 1411.2 sample frame. If we just truncate the .2
1224          * the error will build up over time and eventually the audio will
1225          * substantially lag the video. libsamplerate will keep track of the
1226          * fractional sample & give it to us when appropriate if we give it
1227          * an extra sample of space in the output buffer.
1228          */
1229         count_out = ( duration * audio->config.out.samplerate ) / 90000 + 1;
1230
1231         sync->data.input_frames = count_in;
1232         sync->data.output_frames = count_out;
1233         sync->data.src_ratio = (double)audio->config.out.samplerate /
1234                                (double)audio->config.in.samplerate;
1235
1236         buf = hb_buffer_init( count_out * channel_count );
1237         sync->data.data_in  = (float *) buf_raw->data;
1238         sync->data.data_out = (float *) buf->data;
1239         if( src_process( sync->state, &sync->data ) )
1240         {
1241             /* XXX If this happens, we're screwed */
1242             hb_log( "sync: audio %d src_process failed", audio->id );
1243         }
1244         hb_buffer_close( &buf_raw );
1245
1246         buf->size = sync->data.output_frames_gen * channel_count;
1247         duration = ( sync->data.output_frames_gen * 90000 ) /
1248                    audio->config.out.samplerate;
1249     }
1250     buf->frametype = HB_FRAME_AUDIO;
1251     buf->start = start;
1252     buf->stop  = start + duration;
1253     sync->next_start = start + duration;
1254     return buf;
1255 }
1256
1257 static void InsertSilence( hb_work_object_t * w, int64_t duration )
1258 {
1259     hb_work_private_t * pv = w->private_data;
1260     hb_sync_audio_t *sync = &pv->type.audio;
1261     hb_buffer_t     *buf;
1262     hb_fifo_t       *fifo;
1263
1264     // to keep pass-thru and regular audio in sync we generate silence in
1265     // AC3 frame-sized units. If the silence duration isn't an integer multiple
1266     // of the AC3 frame duration we will truncate or round up depending on
1267     // which minimizes the timing error.
1268     const int frame_dur = ( 90000 * AC3_SAMPLES_PER_FRAME ) /
1269                           w->audio->config.in.samplerate;
1270     int frame_count = ( duration + (frame_dur >> 1) ) / frame_dur;
1271
1272     while ( --frame_count >= 0 )
1273     {
1274         if( w->audio->config.out.codec == HB_ACODEC_AC3_PASS )
1275         {
1276             buf        = hb_buffer_init( sync->ac3_size );
1277             buf->start = sync->next_pts;
1278             buf->stop  = buf->start + frame_dur;
1279             memcpy( buf->data, sync->ac3_buf, buf->size );
1280             fifo = w->audio->priv.fifo_out;
1281         }
1282         else
1283         {
1284             buf = hb_buffer_init( AC3_SAMPLES_PER_FRAME * sizeof( float ) *
1285                                      HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(
1286                                          w->audio->config.out.mixdown) );
1287             buf->start = sync->next_pts;
1288             buf->stop  = buf->start + frame_dur;
1289             memset( buf->data, 0, buf->size );
1290             fifo = w->audio->priv.fifo_sync;
1291         }
1292         buf = OutputAudioFrame( w->audio, buf, sync );
1293         hb_fifo_push( fifo, buf );
1294     }
1295 }
1296
1297 static void UpdateState( hb_work_object_t * w )
1298 {
1299     hb_work_private_t * pv = w->private_data;
1300     hb_sync_video_t   * sync = &pv->type.video;
1301     hb_state_t state;
1302
1303     if( !pv->common->count_frames )
1304     {
1305         sync->st_first = hb_get_date();
1306         pv->job->st_pause_date = -1;
1307         pv->job->st_paused = 0;
1308     }
1309     pv->common->count_frames++;
1310
1311     if( hb_get_date() > sync->st_dates[3] + 1000 )
1312     {
1313         memmove( &sync->st_dates[0], &sync->st_dates[1],
1314                  3 * sizeof( uint64_t ) );
1315         memmove( &sync->st_counts[0], &sync->st_counts[1],
1316                  3 * sizeof( uint64_t ) );
1317         sync->st_dates[3]  = hb_get_date();
1318         sync->st_counts[3] = pv->common->count_frames;
1319     }
1320
1321 #define p state.param.working
1322     state.state = HB_STATE_WORKING;
1323     p.progress  = (float) pv->common->count_frames / (float) sync->count_frames_max;
1324     if( p.progress > 1.0 )
1325     {
1326         p.progress = 1.0;
1327     }
1328     p.rate_cur   = 1000.0 *
1329         (float) ( sync->st_counts[3] - sync->st_counts[0] ) /
1330         (float) ( sync->st_dates[3] - sync->st_dates[0] );
1331     if( hb_get_date() > sync->st_first + 4000 )
1332     {
1333         int eta;
1334         p.rate_avg = 1000.0 * (float) sync->st_counts[3] /
1335             (float) ( sync->st_dates[3] - sync->st_first - pv->job->st_paused);
1336         eta = (float) ( sync->count_frames_max - sync->st_counts[3] ) /
1337             p.rate_avg;
1338         p.hours   = eta / 3600;
1339         p.minutes = ( eta % 3600 ) / 60;
1340         p.seconds = eta % 60;
1341     }
1342     else
1343     {
1344         p.rate_avg = 0.0;
1345         p.hours    = -1;
1346         p.minutes  = -1;
1347         p.seconds  = -1;
1348     }
1349 #undef p
1350
1351     hb_set_state( pv->job->h, &state );
1352 }
1353
1354 static void UpdateSearchState( hb_work_object_t * w, int64_t start )
1355 {
1356     hb_work_private_t * pv = w->private_data;
1357     hb_sync_video_t   * sync = &pv->type.video;
1358     hb_state_t state;
1359     uint64_t now;
1360     double avg;
1361
1362     now = hb_get_date();
1363     if( !pv->common->count_frames )
1364     {
1365         sync->st_first = now;
1366         pv->job->st_pause_date = -1;
1367         pv->job->st_paused = 0;
1368     }
1369     pv->common->count_frames++;
1370
1371 #define p state.param.working
1372     state.state = HB_STATE_SEARCHING;
1373     if ( pv->job->frame_to_start )
1374         p.progress  = (float) pv->common->count_frames / 
1375                       (float) pv->job->frame_to_start;
1376     else if ( pv->job->pts_to_start )
1377         p.progress  = (float) start / (float) pv->job->pts_to_start;
1378     else
1379         p.progress = 0;
1380     if( p.progress > 1.0 )
1381     {
1382         p.progress = 1.0;
1383     }
1384     if (now > sync->st_first)
1385     {
1386         int eta;
1387
1388         if ( pv->job->frame_to_start )
1389         {
1390             avg = 1000.0 * (double)pv->common->count_frames / (now - sync->st_first);
1391             eta = ( pv->job->frame_to_start - pv->common->count_frames ) / avg;
1392         }
1393         else if ( pv->job->pts_to_start )
1394         {
1395             avg = 1000.0 * (double)start / (now - sync->st_first);
1396             eta = ( pv->job->pts_to_start - start ) / avg;
1397         }
1398         p.hours   = eta / 3600;
1399         p.minutes = ( eta % 3600 ) / 60;
1400         p.seconds = eta % 60;
1401     }
1402     else
1403     {
1404         p.rate_avg = 0.0;
1405         p.hours    = -1;
1406         p.minutes  = -1;
1407         p.seconds  = -1;
1408     }
1409 #undef p
1410
1411     hb_set_state( pv->job->h, &state );
1412 }
1413
1414 static void getPtsOffset( hb_work_object_t * w )
1415 {
1416     hb_work_private_t * pv = w->private_data;
1417     int           i ;
1418     int64_t       first_pts = INT64_MAX;
1419
1420     for( i = 0; i < pv->common->pts_count; i++ )
1421     {
1422         if ( pv->common->first_pts[i] < first_pts )
1423             first_pts = pv->common->first_pts[i];
1424     }
1425     pv->common->audio_passthru_slip = pv->common->pts_offset = first_pts;
1426     return;
1427 }
1428
1429 static int checkPtsOffset( hb_work_object_t * w )
1430 {
1431     hb_work_private_t * pv = w->private_data;
1432     int           i ;
1433
1434     for( i = 0; i < pv->common->pts_count; i++ )
1435     {
1436         if ( pv->common->first_pts[i] == INT64_MAX )
1437             return 0;
1438     }
1439     getPtsOffset( w );
1440     return 1;
1441 }