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