OSDN Git Service

Fix another subtitle interleaving botch - for mkv's we want the subtitle in the clust...
[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_fifo_t     * fifo;
25     hb_mux_data_t * mux_data;
26     uint64_t        frames;
27     uint64_t        bytes;
28     mux_fifo_t      mf;
29 } hb_track_t;
30
31 typedef struct
32 {
33     hb_job_t    *job;
34     double      pts;        // end time of next muxing chunk
35     double      interleave; // size (in 90KHz ticks) of media chunks we mux
36     uint32_t    ntracks;    // total number of tracks we're muxing
37     uint32_t    eof;        // bitmask of track with eof
38     uint32_t    rdy;        // bitmask of tracks ready to output
39     uint32_t    allEof;     // valid bits in eof (all tracks)
40     uint32_t    allRdy;     // valid bits in rdy (audio & video tracks)
41     hb_track_t  *track[32]; // array of tracks to mux ('ntrack' elements)
42                             // NOTE- this array could be dynamically allocated
43                             // but the eof & rdy logic has to be changed to
44                             // handle more than 32 tracks anyway so we keep
45                             // it simple and fast.
46 } hb_mux_t;
47
48 // The muxer handles two different kinds of media: Video and audio tracks
49 // are continuous: once they start they generate continuous, consecutive
50 // sequence of bufs until they end. The muxer will time align all continuous
51 // media tracks so that their data will be well interleaved in the output file.
52 // (Smooth, low latency playback with minimal player buffering requires that
53 // data that's going to be presented close together in time also be close
54 // together in the output file). Since HB's audio and video encoders run at
55 // different speeds, the time-aligning involves buffering *all* the continuous
56 // media tracks until a frame with a timestamp beyond the current alignment
57 // point arrives on the slowest fifo (usually the video encoder).
58 //
59 // The other kind of media, subtitles, close-captions, vobsubs and
60 // similar tracks, are intermittent. They generate frames sporadically or on
61 // human time scales (seconds) rather than near the video frame rate (milliseconds).
62 // If intermittent sources were treated like continuous sources huge sections of
63 // audio and video would get buffered waiting for the next subtitle to show up.
64 // To keep this from happening the muxer doesn't wait for intermittent tracks
65 // (essentially it assumes that they will always go through the HB processing
66 // pipeline faster than the associated video). They are still time aligned and
67 // interleaved at the appropriate point in the output file.
68
69 // This routine adds another track for the muxer to process. The media input
70 // stream will be read from HandBrake fifo 'fifo'. Buffers read from that
71 // stream will be time-aligned with all the other media streams then passed
72 // to the container-specific 'mux' routine with argument 'mux_data' (see
73 // routine OutputTrackChunk). 'is_continuous' must be 1 for an audio or video
74 // track and 0 otherwise (see above).
75
76 static void add_mux_track( hb_mux_t *mux, hb_fifo_t *fifo, hb_mux_data_t *mux_data,
77                            int is_continuous )
78 {
79     int max_tracks = sizeof(mux->track) / sizeof(*(mux->track));
80     if ( mux->ntracks >= max_tracks )
81     {
82         hb_error( "add_mux_track: too many tracks (>%d)", max_tracks );
83         return;
84     }
85
86     hb_track_t *track = calloc( sizeof( hb_track_t ), 1 );
87     track->fifo = fifo;
88     track->mux_data = mux_data;
89     track->mf.flen = 8;
90     track->mf.fifo = calloc( sizeof(track->mf.fifo[0]), track->mf.flen );
91
92     int t = mux->ntracks++;
93     mux->track[t] = track;
94     mux->allEof |= 1 << t;
95     mux->allRdy |= is_continuous << t;
96 }
97
98 static void mf_push( hb_track_t *track, hb_buffer_t *buf )
99 {
100     uint32_t mask = track->mf.flen - 1;
101     uint32_t in = track->mf.in;
102     if ( ( ( in + 1 ) & mask ) == ( track->mf.out & mask ) )
103     {
104         // fifo is full - expand it to double the current size.
105         // This is a bit tricky because when we change the size
106         // it changes the modulus (mask) used to convert the in
107         // and out counters to fifo indices. Since existing items
108         // will be referenced at a new location after the expand
109         // we can't just realloc the fifo. If there were
110         // hundreds of fifo entries it would be worth it to have code
111         // for each of the four possible before/after configurations
112         // but these fifos are small so we just allocate a new chunk
113         // of memory then do element by element copies using the old &
114         // new masks then free the old fifo's memory..
115         track->mf.flen *= 2;
116         uint32_t nmask = track->mf.flen - 1;
117         hb_buffer_t **nfifo = malloc( track->mf.flen * sizeof(*nfifo) );
118         int indx = track->mf.out;
119         while ( indx != track->mf.in )
120         {
121             nfifo[indx & nmask] = track->mf.fifo[indx & mask];
122             ++indx;
123         }
124         free( track->mf.fifo );
125         track->mf.fifo = nfifo;
126         mask = nmask;
127     }
128     track->mf.fifo[in & mask] = buf;
129     track->mf.in = in + 1;
130 }
131
132 static hb_buffer_t *mf_pull( hb_track_t *track )
133 {
134     hb_buffer_t *b = NULL;
135     if ( track->mf.out != track->mf.in )
136     {
137         // the fifo isn't empty
138         b = track->mf.fifo[track->mf.out & (track->mf.flen - 1)];
139         ++track->mf.out;
140     }
141     return b;
142 }
143
144 static hb_buffer_t *mf_peek( hb_track_t *track )
145 {
146     return track->mf.out == track->mf.in ?
147                 NULL : track->mf.fifo[track->mf.out & (track->mf.flen - 1)];
148 }
149
150 static void MoveToInternalFifos( hb_mux_t *mux )
151 {
152     int i;
153     int discard = mux->job->pass != 0 && mux->job->pass != 2;
154
155     for( i = 0; i < mux->ntracks; ++i )
156     {
157         if ( ( mux->eof & (1 << i) ) == 0 )
158         {
159             hb_track_t *track = mux->track[i];
160             hb_buffer_t *buf;
161             
162             // move all the buffers on the track's fifo to our internal
163             // fifo so that (a) we don't deadlock in the reader and
164             // (b) we can control how data from multiple tracks is
165             // interleaved in the output file.
166             while ( ( buf = hb_fifo_get( track->fifo ) ) )
167             {
168                 if ( buf->size <= 0 )
169                 {
170                     // EOF - mark this track as done
171                     hb_buffer_close( &buf );
172                     mux->eof |= ( 1 << i );
173                     mux->rdy |= ( 1 << i );
174                     continue;
175                 }
176                 if ( discard )
177                 {
178                     hb_buffer_close( &buf );
179                     continue;
180                 }
181                 mf_push( track, buf );
182                 if ( buf->stop >= mux->pts )
183                 {
184                     // buffer is past our next interleave point so
185                     // note that this track is ready to be output.
186                     mux->rdy |= ( 1 << i );
187                 }
188             }
189         }
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         m->mux( m, track->mux_data, mf_pull( track ) );
200         track->frames += 1;
201         track->bytes  += buf->size;
202         hb_buffer_close( &buf );
203     }
204 }
205
206 static void MuxerFunc( void * _mux )
207 {
208     hb_mux_t    * mux = _mux;
209     hb_job_t    * job = mux->job;
210     hb_title_t  * title = job->title;
211     hb_track_t  * track;
212     int           i;
213     hb_mux_object_t * m = NULL;
214
215     // set up to interleave track data in blocks of 1 video frame time.
216     // (the best case for buffering and playout latency). The container-
217     // specific muxers can reblock this into bigger chunks if necessary.
218     mux->interleave = 90000. * (double)job->vrate_base / (double)job->vrate;
219     mux->pts = mux->interleave;
220
221     /* Get a real muxer */
222     if( job->pass == 0 || job->pass == 2)
223     {
224         switch( job->mux )
225         {
226         case HB_MUX_MP4:
227         case HB_MUX_PSP:
228         case HB_MUX_IPOD:
229             m = hb_mux_mp4_init( job );
230             break;
231         case HB_MUX_AVI:
232             m = hb_mux_avi_init( job );
233             break;
234         case HB_MUX_OGM:
235             m = hb_mux_ogm_init( job );
236             break;
237         case HB_MUX_MKV:
238             m = hb_mux_mkv_init( job );
239             break;
240         default:
241             hb_error( "No muxer selected, exiting" );
242             *job->die = 1;
243         }
244         /* Create file, write headers */
245         if( m )
246         {
247             m->init( m );
248         }
249     }
250
251     /* Build list of fifos we're interested in */
252
253     add_mux_track( mux, job->fifo_mpeg4, job->mux_data, 1 );
254
255     for( i = 0; i < hb_list_count( title->list_audio ); i++ )
256     {
257         hb_audio_t  *audio = hb_list_item( title->list_audio, i );
258         add_mux_track( mux, audio->priv.fifo_out, audio->priv.mux_data, 1 );
259     }
260
261     for( i = 0; i < hb_list_count( title->list_subtitle ); i++ )
262     {
263         hb_subtitle_t  *subtitle = hb_list_item( title->list_subtitle, i );
264
265         if (subtitle->dest != PASSTHRUSUB)
266             continue;
267         add_mux_track( mux, subtitle->fifo_out, subtitle->mux_data, 0 );
268     }
269
270     // The following 'while' is the main muxing loop.
271
272     int thread_sleep_interval = 50;
273     while( !*job->die )
274     {
275         MoveToInternalFifos( mux );
276         if ( ( mux->rdy & mux->allRdy ) != mux->allRdy )
277         {
278             hb_snooze( thread_sleep_interval );
279             continue;
280         }
281
282         // all tracks have at least 'interleave' ticks of data. Output
283         // all that we can in 'interleave' size chunks.
284         while ( ( mux->rdy & mux->allRdy ) == mux->allRdy )
285         {
286             for ( i = 0; i < mux->ntracks; ++i )
287             {
288                 if ( mux->rdy & (1 << i) )
289                 {
290                     track = mux->track[i];
291                     OutputTrackChunk( mux, track, m );
292
293                     // if the track is at eof or still has data that's past
294                     // our next interleave point then leave it marked as rdy.
295                     // Otherwise clear rdy.
296                     if ( ( mux->eof & (1 << i) ) == 0 &&
297                          ( track->mf.out == track->mf.in ||
298                            track->mf.fifo[(track->mf.in-1) & (track->mf.flen-1)]->stop
299                              < mux->pts + mux->interleave ) )
300                     {
301                         mux->rdy &=~ ( 1 << i );
302                     }
303                 }
304             }
305
306             // if all the tracks are at eof we're just purging their
307             // remaining data -- keep going until all internal fifos are empty.
308             if ( mux->eof == mux->allEof )
309             {
310                 for ( i = 0; i < mux->ntracks; ++i )
311                 {
312                     if ( mux->track[i]->mf.out != mux->track[i]->mf.in )
313                     {
314                         break;
315                     }
316                 }
317                 if ( i >= mux->ntracks )
318                 {
319                     goto finished;
320                 }
321             }
322             mux->pts += mux->interleave;
323         }
324     }
325
326     // we're all done muxing -- print final stats and cleanup.
327 finished:
328     if( job->pass == 0 || job->pass == 2 )
329     {
330         struct stat sb;
331         uint64_t bytes_total, frames_total;
332
333 #define p state.param.muxing
334         /* Update the UI */
335         hb_state_t state;
336         state.state   = HB_STATE_MUXING;
337         p.progress = 0;
338         hb_set_state( job->h, &state );
339 #undef p
340         if( m )
341         {
342             m->end( m );
343         }
344
345         if( !stat( job->file, &sb ) )
346         {
347             hb_deep_log( 2, "mux: file size, %lld bytes", (uint64_t) sb.st_size );
348
349             bytes_total  = 0;
350             frames_total = 0;
351             for( i = 0; i < mux->ntracks; ++i )
352             {
353                 track = mux->track[i];
354                 hb_log( "mux: track %d, %lld frames, %lld bytes, %.2f kbps, fifo %d",
355                         i, track->frames, track->bytes,
356                         90000.0 * track->bytes / mux->pts / 125,
357                         track->mf.flen );
358                 if( !i && ( job->vquality < 0.0 || job->vquality > 1.0 ) )
359                 {
360                     /* Video */
361                     hb_deep_log( 2, "mux: video bitrate error, %+lld bytes",
362                             track->bytes - mux->pts * job->vbitrate *
363                             125 / 90000 );
364                 }
365                 bytes_total  += track->bytes;
366                 frames_total += track->frames;
367             }
368
369             if( bytes_total && frames_total )
370             {
371                 hb_deep_log( 2, "mux: overhead, %.2f bytes per frame",
372                         (float) ( sb.st_size - bytes_total ) /
373                         frames_total );
374             }
375         }
376     }
377     
378     if( m )
379     {
380         free( m );
381     }
382
383     for( i = 0; i < mux->ntracks; ++i )
384     {
385         track = mux->track[i];
386         if( track->mux_data )
387         {
388             free( track->mux_data );
389             free( track->mf.fifo );
390         }
391         free( track );
392     }
393
394     free( mux );
395 }
396
397 hb_thread_t * hb_muxer_init( hb_job_t * job )
398 {
399     hb_mux_t * mux = calloc( sizeof( hb_mux_t ), 1 );
400     mux->job = job;
401     return hb_thread_init( "muxer", MuxerFunc, mux,
402                            HB_NORMAL_PRIORITY );
403 }