1 /* $Id: muxcommon.c,v 1.23 2005/03/30 17:27:19 titer Exp $
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. */
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)
25 hb_mux_data_t * mux_data;
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.
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).
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.
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).
76 static void add_mux_track( hb_mux_t *mux, hb_fifo_t *fifo, hb_mux_data_t *mux_data,
79 int max_tracks = sizeof(mux->track) / sizeof(*(mux->track));
80 if ( mux->ntracks >= max_tracks )
82 hb_error( "add_mux_track: too many tracks (>%d)", max_tracks );
86 hb_track_t *track = calloc( sizeof( hb_track_t ), 1 );
88 track->mux_data = mux_data;
90 track->mf.fifo = calloc( sizeof(track->mf.fifo[0]), track->mf.flen );
92 int t = mux->ntracks++;
93 mux->track[t] = track;
94 mux->allEof |= 1 << t;
95 mux->allRdy |= is_continuous << t;
98 static void mf_push( hb_track_t *track, hb_buffer_t *buf )
100 uint32_t mask = track->mf.flen - 1;
101 uint32_t in = track->mf.in;
102 if ( ( ( in + 1 ) & mask ) == ( track->mf.out & mask ) )
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..
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 )
121 nfifo[indx & nmask] = track->mf.fifo[indx & mask];
124 free( track->mf.fifo );
125 track->mf.fifo = nfifo;
128 track->mf.fifo[in & mask] = buf;
129 track->mf.in = in + 1;
132 static hb_buffer_t *mf_pull( hb_track_t *track )
134 hb_buffer_t *b = NULL;
135 if ( track->mf.out != track->mf.in )
137 // the fifo isn't empty
138 b = track->mf.fifo[track->mf.out & (track->mf.flen - 1)];
144 static hb_buffer_t *mf_peek( hb_track_t *track )
146 return track->mf.out == track->mf.in ?
147 NULL : track->mf.fifo[track->mf.out & (track->mf.flen - 1)];
150 static void MoveToInternalFifos( hb_mux_t *mux )
153 int discard = mux->job->pass != 0 && mux->job->pass != 2;
155 for( i = 0; i < mux->ntracks; ++i )
157 if ( ( mux->eof & (1 << i) ) == 0 )
159 hb_track_t *track = mux->track[i];
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 ) ) )
168 if ( buf->size <= 0 )
170 // EOF - mark this track as done
171 hb_buffer_close( &buf );
172 mux->eof |= ( 1 << i );
173 mux->rdy |= ( 1 << i );
178 hb_buffer_close( &buf );
181 mf_push( track, buf );
182 if ( buf->stop >= mux->pts )
184 // buffer is past our next interleave point so
185 // note that this track is ready to be output.
186 mux->rdy |= ( 1 << i );
193 static void OutputTrackChunk( hb_mux_t *mux, hb_track_t *track, hb_mux_object_t *m )
197 while ( ( buf = mf_peek( track ) ) != NULL && buf->start < mux->pts )
199 m->mux( m, track->mux_data, mf_pull( track ) );
201 track->bytes += buf->size;
202 hb_buffer_close( &buf );
206 static void MuxerFunc( void * _mux )
208 hb_mux_t * mux = _mux;
209 hb_job_t * job = mux->job;
210 hb_title_t * title = job->title;
213 hb_mux_object_t * m = NULL;
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;
221 /* Get a real muxer */
222 if( job->pass == 0 || job->pass == 2)
229 m = hb_mux_mp4_init( job );
232 m = hb_mux_avi_init( job );
235 m = hb_mux_ogm_init( job );
238 m = hb_mux_mkv_init( job );
241 hb_error( "No muxer selected, exiting" );
244 /* Create file, write headers */
251 /* Build list of fifos we're interested in */
253 add_mux_track( mux, job->fifo_mpeg4, job->mux_data, 1 );
255 for( i = 0; i < hb_list_count( title->list_audio ); i++ )
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 );
261 for( i = 0; i < hb_list_count( title->list_subtitle ); i++ )
263 hb_subtitle_t *subtitle = hb_list_item( title->list_subtitle, i );
265 if (subtitle->dest != PASSTHRUSUB)
267 add_mux_track( mux, subtitle->fifo_out, subtitle->mux_data, 0 );
270 // The following 'while' is the main muxing loop.
272 int thread_sleep_interval = 50;
275 MoveToInternalFifos( mux );
276 if ( ( mux->rdy & mux->allRdy ) != mux->allRdy )
278 hb_snooze( thread_sleep_interval );
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 )
286 for ( i = 0; i < mux->ntracks; ++i )
288 track = mux->track[i];
289 OutputTrackChunk( mux, track, m );
291 // if the track is at eof or still has data that's past
292 // our next interleave point then leave it marked as rdy.
293 // Otherwise clear rdy.
294 if ( ( mux->eof & (1 << i) ) == 0 &&
295 ( track->mf.out == track->mf.in ||
296 track->mf.fifo[(track->mf.in-1) & (track->mf.flen-1)]->stop
297 < mux->pts + mux->interleave ) )
299 mux->rdy &=~ ( 1 << i );
303 // if all the tracks are at eof we're just purging their
304 // remaining data -- keep going until all internal fifos are empty.
305 if ( mux->eof == mux->allEof )
307 for ( i = 0; i < mux->ntracks; ++i )
309 if ( mux->track[i]->mf.out != mux->track[i]->mf.in )
314 if ( i >= mux->ntracks )
319 mux->pts += mux->interleave;
323 // we're all done muxing -- print final stats and cleanup.
325 if( job->pass == 0 || job->pass == 2 )
328 uint64_t bytes_total, frames_total;
332 state.state = HB_STATE_MUXING;
333 state.param.muxing.progress = 0;
334 hb_set_state( job->h, &state );
341 if( !stat( job->file, &sb ) )
343 hb_deep_log( 2, "mux: file size, %lld bytes", (uint64_t) sb.st_size );
347 for( i = 0; i < mux->ntracks; ++i )
349 track = mux->track[i];
350 hb_log( "mux: track %d, %lld frames, %lld bytes, %.2f kbps, fifo %d",
351 i, track->frames, track->bytes,
352 90000.0 * track->bytes / mux->pts / 125,
354 if( !i && ( job->vquality < 0.0 || job->vquality > 1.0 ) )
357 hb_deep_log( 2, "mux: video bitrate error, %+lld bytes",
358 track->bytes - mux->pts * job->vbitrate *
361 bytes_total += track->bytes;
362 frames_total += track->frames;
365 if( bytes_total && frames_total )
367 hb_deep_log( 2, "mux: overhead, %.2f bytes per frame",
368 (float) ( sb.st_size - bytes_total ) /
379 for( i = 0; i < mux->ntracks; ++i )
381 track = mux->track[i];
382 if( track->mux_data )
384 free( track->mux_data );
385 free( track->mf.fifo );
393 hb_thread_t * hb_muxer_init( hb_job_t * job )
395 hb_mux_t * mux = calloc( sizeof( hb_mux_t ), 1 );
397 return hb_thread_init( "muxer", MuxerFunc, mux,
398 HB_NORMAL_PRIORITY );