OSDN Git Service

WinGui:
[handbrake-jp/handbrake-jp-git.git] / libhb / muxcommon.c
1 /* $Id: muxcommon.c,v 1.23 2005/03/30 17:27:19 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
9 #define MAX_BUFFERING (1024*1024*50)
10
11 struct hb_mux_object_s
12 {
13     HB_MUX_COMMON;
14 };
15
16 typedef struct
17 {
18     hb_buffer_t **fifo;
19     uint32_t    in;     // number of bufs put into fifo
20     uint32_t    out;    // number of bufs taken out of fifo
21     uint32_t    flen;   // fifo length (must be power of two)
22 } mux_fifo_t;
23
24 typedef struct
25 {
26     hb_mux_data_t * mux_data;
27     uint64_t        frames;
28     uint64_t        bytes;
29     mux_fifo_t      mf;
30     int             buffered_size;
31 } hb_track_t;
32
33 typedef struct
34 {
35     hb_lock_t       * mutex;
36     int               ref;
37     int               done;
38     hb_mux_object_t * m;
39     double            pts;        // end time of next muxing chunk
40     double            interleave; // size in 90KHz ticks of media chunks we mux
41     uint32_t          ntracks;    // total number of tracks we're muxing
42     uint32_t          eof;        // bitmask of track with eof
43     uint32_t          rdy;        // bitmask of tracks ready to output
44     uint32_t          allEof;     // valid bits in eof (all tracks)
45     uint32_t          allRdy;     // valid bits in rdy (audio & video tracks)
46     hb_track_t      * track[32];  // array of tracks to mux ('ntrack' elements)
47                                   // NOTE- this array could be dynamically 
48                                   // allocated but the eof & rdy logic has to 
49                                   // be changed to handle more than 32 tracks 
50                                   // anyway so we keep it simple and fast.
51 } hb_mux_t;
52
53 struct hb_work_private_s
54 {
55     hb_job_t * job;
56     int        track;
57     hb_mux_t * mux;
58 };
59
60 // The muxer handles two different kinds of media: Video and audio tracks
61 // are continuous: once they start they generate continuous, consecutive
62 // sequence of bufs until they end. The muxer will time align all continuous
63 // media tracks so that their data will be well interleaved in the output file.
64 // (Smooth, low latency playback with minimal player buffering requires that
65 // data that's going to be presented close together in time also be close
66 // together in the output file). Since HB's audio and video encoders run at
67 // different speeds, the time-aligning involves buffering *all* the continuous
68 // media tracks until a frame with a timestamp beyond the current alignment
69 // point arrives on the slowest fifo (usually the video encoder).
70 //
71 // The other kind of media, subtitles, close-captions, vobsubs and
72 // similar tracks, are intermittent. They generate frames sporadically or on
73 // human time scales (seconds) rather than near the video frame rate (milliseconds).
74 // If intermittent sources were treated like continuous sources huge sections of
75 // audio and video would get buffered waiting for the next subtitle to show up.
76 // To keep this from happening the muxer doesn't wait for intermittent tracks
77 // (essentially it assumes that they will always go through the HB processing
78 // pipeline faster than the associated video). They are still time aligned and
79 // interleaved at the appropriate point in the output file.
80
81 // This routine adds another track for the muxer to process. The media input
82 // stream will be read from HandBrake fifo 'fifo'. Buffers read from that
83 // stream will be time-aligned with all the other media streams then passed
84 // to the container-specific 'mux' routine with argument 'mux_data' (see
85 // routine OutputTrackChunk). 'is_continuous' must be 1 for an audio or video
86 // track and 0 otherwise (see above).
87
88 static void add_mux_track( hb_mux_t *mux, hb_mux_data_t *mux_data,
89                            int is_continuous )
90 {
91     int max_tracks = sizeof(mux->track) / sizeof(*(mux->track));
92     if ( mux->ntracks >= max_tracks )
93     {
94         hb_error( "add_mux_track: too many tracks (>%d)", max_tracks );
95         return;
96     }
97
98     hb_track_t *track = calloc( sizeof( hb_track_t ), 1 );
99     track->mux_data = mux_data;
100     track->mf.flen = 8;
101     track->mf.fifo = calloc( sizeof(track->mf.fifo[0]), track->mf.flen );
102
103     int t = mux->ntracks++;
104     mux->track[t] = track;
105     mux->allEof |= 1 << t;
106     mux->allRdy |= is_continuous << t;
107 }
108
109 static int mf_full( hb_track_t * track )
110 {
111     if ( track->buffered_size > MAX_BUFFERING )
112         return 1;
113
114     return 0;
115 }
116
117 static void mf_push( hb_mux_t * mux, int tk, hb_buffer_t *buf )
118 {
119     hb_track_t * track = mux->track[tk];
120     uint32_t mask = track->mf.flen - 1;
121     uint32_t in = track->mf.in;
122
123     if ( track->buffered_size > MAX_BUFFERING )
124     {
125         mux->rdy = mux->allRdy;
126     }
127     if ( ( ( in + 1 ) & mask ) == ( track->mf.out & mask ) )
128     {
129         // fifo is full - expand it to double the current size.
130         // This is a bit tricky because when we change the size
131         // it changes the modulus (mask) used to convert the in
132         // and out counters to fifo indices. Since existing items
133         // will be referenced at a new location after the expand
134         // we can't just realloc the fifo. If there were
135         // hundreds of fifo entries it would be worth it to have code
136         // for each of the four possible before/after configurations
137         // but these fifos are small so we just allocate a new chunk
138         // of memory then do element by element copies using the old &
139         // new masks then free the old fifo's memory..
140         track->mf.flen *= 2;
141         uint32_t nmask = track->mf.flen - 1;
142         hb_buffer_t **nfifo = malloc( track->mf.flen * sizeof(*nfifo) );
143         int indx = track->mf.out;
144         while ( indx != track->mf.in )
145         {
146             nfifo[indx & nmask] = track->mf.fifo[indx & mask];
147             ++indx;
148         }
149         free( track->mf.fifo );
150         track->mf.fifo = nfifo;
151         mask = nmask;
152     }
153     track->mf.fifo[in & mask] = buf;
154     track->mf.in = in + 1;
155     track->buffered_size += buf->alloc;
156 }
157
158 static hb_buffer_t *mf_pull( hb_track_t *track )
159 {
160     hb_buffer_t *b = NULL;
161     if ( track->mf.out != track->mf.in )
162     {
163         // the fifo isn't empty
164         b = track->mf.fifo[track->mf.out & (track->mf.flen - 1)];
165         ++track->mf.out;
166
167         track->buffered_size -= b->alloc;
168     }
169     return b;
170 }
171
172 static hb_buffer_t *mf_peek( hb_track_t *track )
173 {
174     return track->mf.out == track->mf.in ?
175                 NULL : track->mf.fifo[track->mf.out & (track->mf.flen - 1)];
176 }
177
178 static void MoveToInternalFifos( int tk, hb_mux_t *mux, hb_buffer_t * buf )
179 {
180     // move all the buffers on the track's fifo to our internal
181     // fifo so that (a) we don't deadlock in the reader and
182     // (b) we can control how data from multiple tracks is
183     // interleaved in the output file.
184     mf_push( mux, tk, buf );
185     if ( buf->stop >= mux->pts )
186     {
187         // buffer is past our next interleave point so
188         // note that this track is ready to be output.
189         mux->rdy |= ( 1 << tk );
190     }
191 }
192
193 static void OutputTrackChunk( hb_mux_t *mux, hb_track_t *track, hb_mux_object_t *m )
194 {
195     hb_buffer_t *buf;
196
197     while ( ( buf = mf_peek( track ) ) != NULL && buf->start < mux->pts )
198     {
199         buf = mf_pull( track );
200         track->frames += 1;
201         track->bytes  += buf->size;
202         m->mux( m, track->mux_data, buf );
203     }
204 }
205
206 static int muxWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
207                      hb_buffer_t ** buf_out )
208 {
209     hb_work_private_t * pv = w->private_data;
210     hb_job_t    * job = pv->job;
211     hb_mux_t    * mux = pv->mux;
212     hb_track_t  * track;
213     int           i;
214     hb_buffer_t * buf = *buf_in;
215
216     hb_lock( mux->mutex );
217     if ( mux->done )
218     {
219         hb_unlock( mux->mutex );
220         return HB_WORK_DONE;
221     }
222
223     if ( buf->size <= 0 )
224     {
225         // EOF - mark this track as done
226         hb_buffer_close( &buf );
227         mux->eof |= ( 1 << pv->track );
228         mux->rdy |= ( 1 << pv->track );
229     }
230     else if ( ( job->pass != 0 && job->pass != 2 ) ||
231               ( mux->eof & (1 << pv->track) ) )
232     {
233         hb_buffer_close( &buf );
234     }
235     else
236     {
237         MoveToInternalFifos( pv->track, mux, buf );
238     }
239     *buf_in = NULL;
240
241     if ( ( mux->rdy & mux->allRdy ) != mux->allRdy )
242     {
243         hb_unlock( mux->mutex );
244         return HB_WORK_OK;
245     }
246
247     int more = mux->rdy;
248     // all tracks have at least 'interleave' ticks of data. Output
249     // all that we can in 'interleave' size chunks.
250     while ( (( mux->rdy & mux->allRdy ) == mux->allRdy && more) ||
251             ( mux->eof == mux->allEof ) ) 
252     {
253         more = 0;
254         for ( i = 0; i < mux->ntracks; ++i )
255         {
256             track = mux->track[i];
257             OutputTrackChunk( mux, track, mux->m );
258             if ( mf_full( track ) )
259             {
260                 // If the track's fifo is still full, advance
261                 // the currint interleave point and try again.
262                 mux->rdy = mux->allRdy;
263                 break;
264             }
265
266             // if the track is at eof or still has data that's past
267             // our next interleave point then leave it marked as rdy.
268             // Otherwise clear rdy.
269             if ( ( mux->eof & (1 << i) ) == 0 &&
270                  ( track->mf.out == track->mf.in ||
271                    track->mf.fifo[(track->mf.in-1) & (track->mf.flen-1)]->stop
272                      < mux->pts + mux->interleave ) )
273             {
274                 mux->rdy &=~ ( 1 << i );
275             }
276             if ( track->mf.out != track->mf.in )
277             {
278                 more |= ( 1 << i );
279             }
280         }
281
282         // if all the tracks are at eof we're just purging their
283         // remaining data -- keep going until all internal fifos are empty.
284         if ( mux->eof == mux->allEof )
285         {
286             for ( i = 0; i < mux->ntracks; ++i )
287             {
288                 if ( mux->track[i]->mf.out != mux->track[i]->mf.in )
289                 {
290                     break;
291                 }
292             }
293             if ( i >= mux->ntracks )
294             {
295                 mux->done = 1;
296                 hb_unlock( mux->mutex );
297                 return HB_WORK_DONE;
298             }
299         }
300         mux->pts += mux->interleave;
301     }
302     hb_unlock( mux->mutex );
303     return HB_WORK_OK;
304 }
305
306 void muxClose( hb_work_object_t * w )
307 {
308     hb_work_private_t * pv = w->private_data;
309     hb_mux_t    * mux = pv->mux;
310     hb_job_t    * job = pv->job;
311     hb_track_t  * track;
312     int           i;
313
314     hb_lock( mux->mutex );
315     if ( --mux->ref == 0 )
316     {
317         // Update state before closing muxer.  Closing the muxer
318         // may initiate optimization which can take a while and
319         // we want the muxing state to be visible while this is
320         // happening.
321         if( job->pass == 0 || job->pass == 2 )
322         {
323             /* Update the UI */
324             hb_state_t state;
325             state.state = HB_STATE_MUXING;
326             state.param.muxing.progress = 0;
327             hb_set_state( job->h, &state );
328         }
329
330         if( mux->m )
331         {
332             mux->m->end( mux->m );
333             free( mux->m );
334         }
335
336         // we're all done muxing -- print final stats and cleanup.
337         if( job->pass == 0 || job->pass == 2 )
338         {
339             struct stat sb;
340             uint64_t bytes_total, frames_total;
341
342             if( !stat( job->file, &sb ) )
343             {
344                 hb_deep_log( 2, "mux: file size, %"PRId64" bytes", (uint64_t) sb.st_size );
345
346                 bytes_total  = 0;
347                 frames_total = 0;
348                 for( i = 0; i < mux->ntracks; ++i )
349                 {
350                     track = mux->track[i];
351                     hb_log( "mux: track %d, %"PRId64" frames, %"PRId64" bytes, %.2f kbps, fifo %d",
352                             i, track->frames, track->bytes,
353                             90000.0 * track->bytes / mux->pts / 125,
354                             track->mf.flen );
355                     if( !i && ( job->vquality < 0.0 || job->vquality > 1.0 ) )
356                     {
357                         /* Video */
358                         hb_deep_log( 2, "mux: video bitrate error, %+"PRId64" bytes",
359                                 (int64_t)(track->bytes - mux->pts * job->vbitrate * 125 / 90000) );
360                     }
361                     bytes_total  += track->bytes;
362                     frames_total += track->frames;
363                 }
364
365                 if( bytes_total && frames_total )
366                 {
367                     hb_deep_log( 2, "mux: overhead, %.2f bytes per frame",
368                             (float) ( sb.st_size - bytes_total ) /
369                             frames_total );
370                 }
371             }
372         }
373     
374         for( i = 0; i < mux->ntracks; ++i )
375         {
376             hb_buffer_t * b;
377             track = mux->track[i];
378             while ( (b = mf_pull( track )) != NULL )
379             {
380                 hb_buffer_close( &b );
381             }
382             if( track->mux_data )
383             {
384                 free( track->mux_data );
385                 free( track->mf.fifo );
386             }
387             free( track );
388         }
389         hb_unlock( mux->mutex );
390         hb_lock_close( &mux->mutex );
391         free( mux );
392     }
393     else
394     {
395         hb_unlock( mux->mutex );
396     }
397     free( pv );
398     w->private_data = NULL;
399 }
400
401 static void mux_loop( void * _w )
402 {
403     hb_work_object_t  * w = _w;
404     hb_work_private_t * pv = w->private_data;
405     hb_job_t          * job = pv->job;
406     hb_buffer_t       * buf_in;
407
408     while ( !*job->die && w->status != HB_WORK_DONE )
409     {
410         buf_in = hb_fifo_get_wait( w->fifo_in );
411         if ( pv->mux->done )
412             break;
413         if ( buf_in == NULL )
414             continue;
415         if ( *job->die )
416         {
417             if( buf_in )
418             {
419                 hb_buffer_close( &buf_in );
420             }
421             break;
422         }
423
424         w->status = w->work( w, &buf_in, NULL );
425         if( buf_in )
426         {
427             hb_buffer_close( &buf_in );
428         }
429     }
430 }
431
432 hb_work_object_t * hb_muxer_init( hb_job_t * job )
433 {
434     hb_title_t  * title = job->title;
435     int           i;
436     hb_mux_t    * mux = calloc( sizeof( hb_mux_t ), 1 );
437     hb_work_object_t  * w;
438     hb_work_object_t  * muxer;
439
440     mux->mutex = hb_lock_init();
441
442     // set up to interleave track data in blocks of 1 video frame time.
443     // (the best case for buffering and playout latency). The container-
444     // specific muxers can reblock this into bigger chunks if necessary.
445     mux->interleave = 90000. * (double)job->vrate_base / (double)job->vrate;
446     mux->pts = mux->interleave;
447
448     /* Get a real muxer */
449     if( job->pass == 0 || job->pass == 2)
450     {
451         switch( job->mux )
452         {
453         case HB_MUX_MP4:
454             mux->m = hb_mux_mp4_init( job );
455             break;
456         case HB_MUX_MKV:
457             mux->m = hb_mux_mkv_init( job );
458             break;
459         default:
460             hb_error( "No muxer selected, exiting" );
461             *job->die = 1;
462             return NULL;
463         }
464         /* Create file, write headers */
465         if( mux->m )
466         {
467             mux->m->init( mux->m );
468         }
469     }
470
471     /* Initialize the work objects that will receive fifo data */
472
473     muxer = hb_get_work( WORK_MUX );
474     muxer->private_data = calloc( sizeof( hb_work_private_t ), 1 );
475     muxer->private_data->job = job;
476     muxer->private_data->mux = mux;
477     mux->ref++;
478     muxer->private_data->track = mux->ntracks;
479     muxer->fifo_in = job->fifo_mpeg4;
480     add_mux_track( mux, job->mux_data, 1 );
481     muxer->done = &muxer->private_data->mux->done;
482
483     for( i = 0; i < hb_list_count( title->list_audio ); i++ )
484     {
485         hb_audio_t  *audio = hb_list_item( title->list_audio, i );
486
487         w = hb_get_work( WORK_MUX );
488         w->private_data = calloc( sizeof( hb_work_private_t ), 1 );
489         w->private_data->job = job;
490         w->private_data->mux = mux;
491         mux->ref++;
492         w->private_data->track = mux->ntracks;
493         w->fifo_in = audio->priv.fifo_out;
494         add_mux_track( mux, audio->priv.mux_data, 1 );
495         w->done = &job->done;
496         hb_list_add( job->list_work, w );
497         w->thread = hb_thread_init( w->name, mux_loop, w, HB_NORMAL_PRIORITY );
498     }
499
500     for( i = 0; i < hb_list_count( title->list_subtitle ); i++ )
501     {
502         hb_subtitle_t  *subtitle = hb_list_item( title->list_subtitle, i );
503
504         if (subtitle->config.dest != PASSTHRUSUB)
505             continue;
506
507         w = hb_get_work( WORK_MUX );
508         w->private_data = calloc( sizeof( hb_work_private_t ), 1 );
509         w->private_data->job = job;
510         w->private_data->mux = mux;
511         mux->ref++;
512         w->private_data->track = mux->ntracks;
513         w->fifo_in = subtitle->fifo_out;
514         add_mux_track( mux, subtitle->mux_data, 0 );
515         w->done = &job->done;
516         hb_list_add( job->list_work, w );
517         w->thread = hb_thread_init( w->name, mux_loop, w, HB_NORMAL_PRIORITY );
518     }
519     return muxer;
520 }
521
522 // muxInit does nothing because the muxer has a special initializer
523 // that takes care of initializing all muxer work objects
524 static int muxInit( hb_work_object_t * w, hb_job_t * job )
525 {
526     return 0;
527 }
528
529 hb_work_object_t hb_muxer =
530 {
531     WORK_MUX,
532     "Muxer",
533     muxInit,
534     muxWork,
535     muxClose
536 };
537