OSDN Git Service

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