summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libhb/deca52.c9
-rw-r--r--libhb/decavcodec.c16
-rw-r--r--libhb/decdca.c8
-rw-r--r--libhb/declpcm.c11
-rw-r--r--libhb/decsub.c9
-rw-r--r--libhb/encavcodec.c6
-rw-r--r--libhb/encfaac.c94
-rw-r--r--libhb/enclame.c8
-rw-r--r--libhb/enctheora.c26
-rw-r--r--libhb/encvorbis.c8
-rw-r--r--libhb/encx264.c465
-rw-r--r--libhb/encxvid.c8
-rw-r--r--libhb/muxcommon.c104
-rw-r--r--libhb/muxmp4.c52
-rw-r--r--libhb/reader.c14
-rw-r--r--libhb/sync.c53
-rw-r--r--libhb/work.c11
17 files changed, 520 insertions, 382 deletions
diff --git a/libhb/deca52.c b/libhb/deca52.c
index 1495611da..c0651fad2 100644
--- a/libhb/deca52.c
+++ b/libhb/deca52.c
@@ -144,11 +144,16 @@ static int deca52Work( hb_work_object_t * w, hb_buffer_t ** buf_in,
hb_work_private_t * pv = w->private_data;
hb_buffer_t * buf;
- if( buf_in && *buf_in )
+ if ( (*buf_in)->size <= 0 )
{
- pv->sequence = (*buf_in)->sequence;
+ /* EOF on input stream - send it downstream & say that we're done */
+ *buf_out = *buf_in;
+ *buf_in = NULL;
+ return HB_WORK_DONE;
}
+ pv->sequence = (*buf_in)->sequence;
+
hb_list_add( pv->list, *buf_in );
*buf_in = NULL;
diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c
index c49dcc79c..2ad3993a0 100644
--- a/libhb/decavcodec.c
+++ b/libhb/decavcodec.c
@@ -164,6 +164,14 @@ static int decavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
unsigned char *parser_output_buffer;
int parser_output_buffer_len;
+ if ( (*buf_in)->size <= 0 )
+ {
+ /* EOF on input stream - send it downstream & say that we're done */
+ *buf_out = *buf_in;
+ *buf_in = NULL;
+ return HB_WORK_DONE;
+ }
+
*buf_out = NULL;
cur = ( in->start < 0 )? pv->pts_next : in->start;
@@ -842,6 +850,14 @@ static void decodeAudio( hb_work_private_t *pv, uint8_t *data, int size )
static int decavcodecaiWork( hb_work_object_t *w, hb_buffer_t **buf_in,
hb_buffer_t **buf_out )
{
+ if ( (*buf_in)->size <= 0 )
+ {
+ /* EOF on input stream - send it downstream & say that we're done */
+ *buf_out = *buf_in;
+ *buf_in = NULL;
+ return HB_WORK_DONE;
+ }
+
hb_work_private_t *pv = w->private_data;
if ( ! pv->context )
{
diff --git a/libhb/decdca.c b/libhb/decdca.c
index a326031dd..0c905af10 100644
--- a/libhb/decdca.c
+++ b/libhb/decdca.c
@@ -113,6 +113,14 @@ static int decdcaWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
hb_work_private_t * pv = w->private_data;
hb_buffer_t * buf;
+ if ( (*buf_in)->size <= 0 )
+ {
+ /* EOF on input stream - send it downstream & say that we're done */
+ *buf_out = *buf_in;
+ *buf_in = NULL;
+ return HB_WORK_DONE;
+ }
+
hb_list_add( pv->list, *buf_in );
*buf_in = NULL;
diff --git a/libhb/declpcm.c b/libhb/declpcm.c
index 3220d3da5..50a5a128d 100644
--- a/libhb/declpcm.c
+++ b/libhb/declpcm.c
@@ -133,14 +133,15 @@ static int declpcmWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
hb_buffer_t ** buf_out )
{
hb_work_private_t * pv = w->private_data;
- hb_buffer_t *in;
+ hb_buffer_t *in = *buf_in;
hb_buffer_t *buf = NULL;
- /* need an input buffer to do anything */
- if( ! buf_in || ! ( in = *buf_in ) )
+ if ( in->size <= 0 )
{
- *buf_out = buf;
- return HB_WORK_OK;
+ /* EOF on input stream - send it downstream & say that we're done */
+ *buf_out = in;
+ *buf_in = NULL;
+ return HB_WORK_DONE;
}
pv->sequence = in->sequence;
diff --git a/libhb/decsub.c b/libhb/decsub.c
index 4b6b873fc..98ffa1a0d 100644
--- a/libhb/decsub.c
+++ b/libhb/decsub.c
@@ -51,9 +51,16 @@ int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
{
hb_work_private_t * pv = w->private_data;
hb_buffer_t * in = *buf_in;
-
int size_sub, size_rle;
+ if ( in->size <= 0 )
+ {
+ /* EOF on input stream - send it downstream & say that we're done */
+ *buf_out = in;
+ *buf_in = NULL;
+ return HB_WORK_DONE;
+ }
+
pv->stream_id = in->id;
size_sub = ( in->data[0] << 8 ) | in->data[1];
diff --git a/libhb/encavcodec.c b/libhb/encavcodec.c
index 2d3f33418..f3837b3e7 100644
--- a/libhb/encavcodec.c
+++ b/libhb/encavcodec.c
@@ -191,9 +191,11 @@ int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
AVFrame * frame;
hb_buffer_t * in = *buf_in, * buf;
- if(!in->data)
+ if ( in->size <= 0 )
{
- *buf_out = NULL;
+ /* EOF on input - send it downstream & say we're done */
+ *buf_out = in;
+ *buf_in = NULL;
return HB_WORK_DONE;
}
diff --git a/libhb/encfaac.c b/libhb/encfaac.c
index 7e06a1408..645628a8e 100644
--- a/libhb/encfaac.c
+++ b/libhb/encfaac.c
@@ -16,12 +16,11 @@ struct hb_work_private_s
unsigned long input_samples;
unsigned long output_bytes;
uint8_t * buf;
-
+ uint8_t * obuf;
hb_list_t * list;
int64_t pts;
-
+ int64_t framedur;
int out_discrete_channels;
-
};
int encfaacInit( hb_work_object_t *, hb_job_t * );
@@ -57,9 +56,12 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job )
/* pass the number of channels used into the private work data */
pv->out_discrete_channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown);
- pv->faac = faacEncOpen( audio->config.out.samplerate, pv->out_discrete_channels, &pv->input_samples,
- &pv->output_bytes );
+ pv->faac = faacEncOpen( audio->config.out.samplerate, pv->out_discrete_channels,
+ &pv->input_samples, &pv->output_bytes );
pv->buf = malloc( pv->input_samples * sizeof( float ) );
+ pv->obuf = malloc( pv->output_bytes );
+ pv->framedur = 90000LL * pv->input_samples /
+ ( audio->config.out.samplerate * pv->out_discrete_channels );
cfg = faacEncGetCurrentConfiguration( pv->faac );
cfg->mpegVersion = MPEG4;
@@ -113,7 +115,6 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job )
free( bytes );
pv->list = hb_list_init();
- pv->pts = -1;
return 0;
}
@@ -128,6 +129,7 @@ void encfaacClose( hb_work_object_t * w )
hb_work_private_t * pv = w->private_data;
faacEncClose( pv->faac );
free( pv->buf );
+ free( pv->obuf );
hb_list_empty( &pv->list );
free( pv );
w->private_data = NULL;
@@ -141,9 +143,6 @@ void encfaacClose( hb_work_object_t * w )
static hb_buffer_t * Encode( hb_work_object_t * w )
{
hb_work_private_t * pv = w->private_data;
- hb_audio_t * audio = w->audio;
- hb_buffer_t * buf;
- uint64_t pts, pos;
if( hb_list_bytes( pv->list ) < pv->input_samples * sizeof( float ) )
{
@@ -151,31 +150,64 @@ static hb_buffer_t * Encode( hb_work_object_t * w )
return NULL;
}
+ uint64_t pts, pos;
hb_list_getbytes( pv->list, pv->buf, pv->input_samples * sizeof( float ),
&pts, &pos );
+ int size = faacEncEncode( pv->faac, (int32_t *)pv->buf, pv->input_samples,
+ pv->obuf, pv->output_bytes );
- buf = hb_buffer_init( pv->output_bytes );
- buf->start = pts + 90000 * pos / pv->out_discrete_channels / sizeof( float ) / audio->config.out.samplerate;
- buf->stop = buf->start + 90000 * pv->input_samples / audio->config.out.samplerate / pv->out_discrete_channels;
- buf->size = faacEncEncode( pv->faac, (int32_t *) pv->buf,
- pv->input_samples, buf->data, pv->output_bytes );
- buf->frametype = HB_FRAME_AUDIO;
-
- if( !buf->size )
+ // AAC needs four frames before it can start encoding so we'll get nothing
+ // on the first three calls to the encoder.
+ if ( size > 0 )
{
- /* Encoding was successful but we got no data. Try to encode
- more */
- hb_buffer_close( &buf );
- return Encode( w );
+ hb_buffer_t * buf = hb_buffer_init( size );
+ memcpy( buf->data, pv->obuf, size );
+ buf->size = size;
+ buf->start = pv->pts;
+ pv->pts += pv->framedur;
+ buf->stop = pv->pts;
+ buf->frametype = HB_FRAME_AUDIO;
+ return buf;
}
- else if( buf->size < 0 )
+ return NULL;
+}
+
+static hb_buffer_t *Flush( hb_work_object_t *w, hb_buffer_t *bufin )
+{
+ hb_work_private_t *pv = w->private_data;
+
+ // pad whatever data we have out to four input frames.
+ int nbytes = hb_list_bytes( pv->list );
+ int pad = pv->input_samples * sizeof(float) * 4 - nbytes;
+ if ( pad > 0 )
{
- hb_log( "faacEncEncode failed" );
- hb_buffer_close( &buf );
- return NULL;
+ hb_buffer_t *tmp = hb_buffer_init( pad );
+ memset( tmp->data, 0, pad );
+ hb_list_add( pv->list, tmp );
}
- return buf;
+ // There are up to three frames buffered in the encoder plus one
+ // in our list buffer so four calls to Encode should get them all.
+ hb_buffer_t *bufout = NULL, *buf = NULL;
+ while ( hb_list_bytes( pv->list ) >= pv->input_samples * sizeof(float) )
+ {
+ hb_buffer_t *b = Encode( w );
+ if ( b )
+ {
+ if ( bufout == NULL )
+ {
+ bufout = b;
+ }
+ else
+ {
+ buf->next = b;
+ }
+ buf = b;
+ }
+ }
+ // add the eof marker to the end of our buf chain
+ buf->next = bufin;
+ return bufout;
}
/***********************************************************************
@@ -189,6 +221,16 @@ int encfaacWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
hb_work_private_t * pv = w->private_data;
hb_buffer_t * buf;
+ if ( (*buf_in)->size <= 0 )
+ {
+ // EOF on input. Finish encoding what we have buffered then send
+ // it & the eof downstream.
+
+ *buf_out = Flush( w, *buf_in );
+ *buf_in = NULL;
+ return HB_WORK_DONE;
+ }
+
hb_list_add( pv->list, *buf_in );
*buf_in = NULL;
diff --git a/libhb/enclame.c b/libhb/enclame.c
index 24e9542f4..8f4defcc5 100644
--- a/libhb/enclame.c
+++ b/libhb/enclame.c
@@ -140,6 +140,14 @@ int enclameWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
hb_work_private_t * pv = w->private_data;
hb_buffer_t * buf;
+ if ( (*buf_in)->size <= 0 )
+ {
+ /* EOF on input - send it downstream & say we're done */
+ *buf_out = *buf_in;
+ *buf_in = NULL;
+ return HB_WORK_DONE;
+ }
+
hb_list_add( pv->list, *buf_in );
*buf_in = NULL;
diff --git a/libhb/enctheora.c b/libhb/enctheora.c
index 59414687c..274887f9f 100644
--- a/libhb/enctheora.c
+++ b/libhb/enctheora.c
@@ -122,23 +122,22 @@ int enctheoraWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
hb_buffer_t * in = *buf_in, * buf;
yuv_buffer yuv;
ogg_packet op;
- static int last_p = 0;
- memset(&op, 0, sizeof(op));
- memset(&yuv, 0, sizeof(yuv));
-
- /* If this is the last empty frame, we're done */
- if(!in->data)
+ if ( in->size <= 0 )
{
- if (!last_p)
- {
- last_p++;
- goto finish;
- }
- *buf_out = NULL;
+ // EOF on input - send it downstream & say we're done.
+ // XXX may need to flush packets via a call to
+ // theora_encode_packetout(&pv->theora, 1, &op);
+ // but we don't have a timestamp to put on those packets so we
+ // drop them for now.
+ *buf_out = in;
+ *buf_in = NULL;
return HB_WORK_DONE;
}
+ memset(&op, 0, sizeof(op));
+ memset(&yuv, 0, sizeof(yuv));
+
yuv.y_width = job->width;
yuv.y_height = job->height;
yuv.y_stride = job->width;
@@ -153,8 +152,7 @@ int enctheoraWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
theora_encode_YUVin(&pv->theora, &yuv);
-finish:
- theora_encode_packetout(&pv->theora, last_p, &op);
+ theora_encode_packetout(&pv->theora, 0, &op);
buf = hb_buffer_init( op.bytes + sizeof(op) );
memcpy(buf->data, &op, sizeof(op));
diff --git a/libhb/encvorbis.c b/libhb/encvorbis.c
index 5ba073291..47a6077a0 100644
--- a/libhb/encvorbis.c
+++ b/libhb/encvorbis.c
@@ -252,6 +252,14 @@ int encvorbisWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
hb_work_private_t * pv = w->private_data;
hb_buffer_t * buf;
+ if ( (*buf_in)->size <= 0 )
+ {
+ /* EOF on input - send it downstream & say we're done */
+ *buf_out = *buf_in;
+ *buf_in = NULL;
+ return HB_WORK_DONE;
+ }
+
hb_list_add( pv->list, *buf_in );
*buf_in = NULL;
diff --git a/libhb/encx264.c b/libhb/encx264.c
index 57a2fe281..caeccb646 100644
--- a/libhb/encx264.c
+++ b/libhb/encx264.c
@@ -30,16 +30,16 @@ hb_work_object_t hb_encx264 =
* to x264_encoder_encode. Since frames are uniquely identified by their
* timestamp, we use some bits of the timestamp as an index. The LSB is
* chosen so that two successive frames will have different values in the
- * bits over any plausible range of frame rates. (Starting with bit 9 allows
- * any frame rate slower than 175fps.) The MSB determines the size of the array.
+ * bits over any plausible range of frame rates. (Starting with bit 8 allows
+ * any frame rate slower than 352fps.) The MSB determines the size of the array.
* It is chosen so that two frames can't use the same slot during the
* encoder's max frame delay (set by the standard as 16 frames) and so
* that, up to some minimum frame rate, frames are guaranteed to map to
- * different slots. (An MSB of 16 which is 2^(16-9+1) = 256 slots guarantees
- * no collisions down to a rate of 1.4 fps).
+ * different slots. (An MSB of 17 which is 2^(17-8+1) = 1024 slots guarantees
+ * no collisions down to a rate of .7 fps).
*/
-#define FRAME_INFO_MAX2 (9) // 2^9 = 512; 90000/512 = 175 frames/sec
-#define FRAME_INFO_MIN2 (16) // 2^16 = 65536; 90000/65536 = 1.4 frames/sec
+#define FRAME_INFO_MAX2 (8) // 2^8 = 256; 90000/256 = 352 frames/sec
+#define FRAME_INFO_MIN2 (17) // 2^17 = 128K; 90000/131072 = 1.4 frames/sec
#define FRAME_INFO_SIZE (1 << (FRAME_INFO_MIN2 - FRAME_INFO_MAX2 + 1))
#define FRAME_INFO_MASK (FRAME_INFO_SIZE - 1)
@@ -377,228 +377,311 @@ static int64_t get_frame_duration( hb_work_private_t * pv, int64_t pts )
return pv->frame_info[i].duration;
}
-int encx264Work( hb_work_object_t * w, hb_buffer_t ** buf_in,
- hb_buffer_t ** buf_out )
+static hb_buffer_t *nal_encode( hb_work_object_t *w, x264_picture_t *pic_out,
+ int i_nal, x264_nal_t *nal )
{
- hb_work_private_t * pv = w->private_data;
- hb_job_t * job = pv->job;
- hb_buffer_t * in = *buf_in, * buf;
- x264_picture_t pic_out;
- int i_nal;
- x264_nal_t * nal;
- int i;
-
- if( in->data )
+ hb_buffer_t *buf = NULL;
+ hb_work_private_t *pv = w->private_data;
+ hb_job_t *job = pv->job;
+
+ /* Get next DTS value to use */
+ int64_t dts_start = pv->dts_next;
+
+ /* compute the stop time based on the original frame's duration */
+ int64_t dts_stop = dts_start + get_frame_duration( pv, pic_out->i_pts );
+ pv->dts_next = dts_stop;
+
+ /* Should be way too large */
+ buf = hb_buffer_init( 3 * job->width * job->height / 2 );
+ buf->size = 0;
+ buf->frametype = 0;
+ buf->start = dts_start;
+ buf->stop = dts_stop;
+
+ /* Store the output presentation time stamp from x264 for use by muxmp4
+ in off-setting b-frames with the CTTS atom. */
+ buf->renderOffset = pic_out->i_pts - dts_start + pv->init_delay;
+ if ( buf->renderOffset < 0 )
{
- /*
- * Point x264 at our current buffers Y(UV) data.
- */
- pv->pic_in.img.plane[0] = in->data;
-
- if( job->grayscale )
- {
- /* XXX x264 has currently no option for grayscale encoding */
- memset( pv->pic_in.img.plane[1], 0x80, job->width * job->height / 4 );
- memset( pv->pic_in.img.plane[2], 0x80, job->width * job->height / 4 );
- }
- else
+ if ( dts_start - pic_out->i_pts > pv->max_delay )
{
- /*
- * Point x264 at our buffers (Y)UV data
- */
- pv->pic_in.img.plane[1] = in->data + job->width * job->height;
- pv->pic_in.img.plane[2] = in->data + 5 * job->width *
- job->height / 4;
+ pv->max_delay = dts_start - pic_out->i_pts;
+ hb_log( "encx264: init_delay too small: "
+ "is %lld need %lld", pv->init_delay,
+ pv->max_delay );
}
+ buf->renderOffset = 0;
+ }
- if( pv->dts_next == -1 )
+ /* Encode all the NALs we were given into buf.
+ NOTE: This code assumes one video frame per NAL (but there can
+ be other stuff like SPS and/or PPS). If there are multiple
+ frames we only get the duration of the first which will
+ eventually screw up the muxer & decoder. */
+ int i;
+ for( i = 0; i < i_nal; i++ )
+ {
+ int data = buf->alloc - buf->size;
+ int size = x264_nal_encode( buf->data + buf->size, &data, 1, &nal[i] );
+ if( size < 1 )
{
- /* we don't have a start time yet so use the first frame's
- * start. All other frame times will be determined by the
- * sum of the prior output frame durations in *DTS* order
- * (not by the order they arrive here). This timing change is
- * essential for VFR with b-frames but a complete nop otherwise.
- */
- pv->dts_next = in->start;
+ continue;
}
- if( in->new_chap && job->chapter_markers )
+
+ if( job->mux & HB_MUX_AVI )
{
- /* chapters have to start with an IDR frame so request that this
- frame be coded as IDR. Since there may be up to 16 frames
- currently buffered in the encoder remember the timestamp so
- when this frame finally pops out of the encoder we'll mark
- its buffer as the start of a chapter. */
- pv->pic_in.i_type = X264_TYPE_IDR;
- if( pv->next_chap == 0 )
+ if( nal[i].i_ref_idc == NAL_PRIORITY_HIGHEST )
{
- pv->next_chap = in->start;
- pv->chap_mark = in->new_chap;
+ buf->frametype = HB_FRAME_KEY;
}
- /* don't let 'work_loop' put a chapter mark on the wrong buffer */
- in->new_chap = 0;
+ buf->size += size;
+ continue;
}
- else
+
+ /* H.264 in .mp4 or .mkv */
+ int naltype = buf->data[buf->size+4] & 0x1f;
+ if ( naltype == 0x7 || naltype == 0x8 )
{
- pv->pic_in.i_type = X264_TYPE_AUTO;
+ // Sequence Parameter Set & Program Parameter Set go in the
+ // mp4 header so skip them here
+ continue;
}
- pv->pic_in.i_qpplus1 = 0;
- /* XXX this is temporary debugging code to check that the upstream
- * modules (render & sync) have generated a continuous, self-consistent
- * frame stream with the current frame's start time equal to the
- * previous frame's stop time.
- */
- if( pv->last_stop != in->start )
+ /* H.264 in mp4 (stolen from mp4creator) */
+ buf->data[buf->size+0] = ( ( size - 4 ) >> 24 ) & 0xFF;
+ buf->data[buf->size+1] = ( ( size - 4 ) >> 16 ) & 0xFF;
+ buf->data[buf->size+2] = ( ( size - 4 ) >> 8 ) & 0xFF;
+ buf->data[buf->size+3] = ( ( size - 4 ) >> 0 ) & 0xFF;
+
+ /* Decide what type of frame we have. */
+ switch( pic_out->i_type )
{
- hb_log("encx264 input continuity err: last stop %lld start %lld",
- pv->last_stop, in->start);
+ case X264_TYPE_IDR:
+ buf->frametype = HB_FRAME_IDR;
+ /* if we have a chapter marker pending and this
+ frame's presentation time stamp is at or after
+ the marker's time stamp, use this as the
+ chapter start. */
+ if( pv->next_chap != 0 && pv->next_chap <= pic_out->i_pts )
+ {
+ pv->next_chap = 0;
+ buf->new_chap = pv->chap_mark;
+ }
+ break;
+
+ case X264_TYPE_I:
+ buf->frametype = HB_FRAME_I;
+ break;
+
+ case X264_TYPE_P:
+ buf->frametype = HB_FRAME_P;
+ break;
+
+ case X264_TYPE_B:
+ buf->frametype = HB_FRAME_B;
+ break;
+
+ /* This is for b-pyramid, which has reference b-frames
+ However, it doesn't seem to ever be used... */
+ case X264_TYPE_BREF:
+ buf->frametype = HB_FRAME_BREF;
+ break;
+
+ // If it isn't the above, what type of frame is it??
+ default:
+ buf->frametype = 0;
+ break;
}
- pv->last_stop = in->stop;
- // Remember info about this frame that we need to pass across
- // the x264_encoder_encode call (since it reorders frames).
- save_frame_info( pv, in );
+ /* Since libx264 doesn't tell us when b-frames are
+ themselves reference frames, figure it out on our own. */
+ if( (buf->frametype == HB_FRAME_B) &&
+ (nal[i].i_ref_idc != NAL_PRIORITY_DISPOSABLE) )
+ buf->frametype = HB_FRAME_BREF;
- /* Feed the input DTS to x264 so it can figure out proper output PTS */
- pv->pic_in.i_pts = in->start;
+ buf->size += size;
+ }
+ // make sure we found at least one video frame
+ if ( buf->size <= 0 )
+ {
+ // no video: back up the output time stamp then free the buf
+ pv->dts_next = buf->start;
+ hb_buffer_close( &buf );
+ }
+ return buf;
+}
+
+static hb_buffer_t *x264_encode( hb_work_object_t *w, hb_buffer_t *in )
+{
+ hb_work_private_t *pv = w->private_data;
+ hb_job_t *job = pv->job;
- x264_encoder_encode( pv->x264, &nal, &i_nal,
- &pv->pic_in, &pic_out );
+ /* Point x264 at our current buffers Y(UV) data. */
+ pv->pic_in.img.plane[0] = in->data;
+
+ if( job->grayscale )
+ {
+ /* XXX x264 has currently no option for grayscale encoding */
+ memset( pv->pic_in.img.plane[1], 0x80, job->width * job->height / 4 );
+ memset( pv->pic_in.img.plane[2], 0x80, job->width * job->height / 4 );
}
else
{
- x264_encoder_encode( pv->x264, &nal, &i_nal,
- NULL, &pic_out );
- /* No more delayed B frames */
- if( i_nal == 0 )
- {
- *buf_out = NULL;
- return HB_WORK_DONE;
- }
- else
+ /* Point x264 at our buffers (Y)UV data */
+ pv->pic_in.img.plane[1] = in->data + job->width * job->height;
+ pv->pic_in.img.plane[2] = in->data + 5 * job->width * job->height / 4;
+ }
+
+ if( pv->dts_next == -1 )
+ {
+ /* we don't have a start time yet so use the first frame's
+ * start. All other frame times will be determined by the
+ * sum of the prior output frame durations in *DTS* order
+ * (not by the order they arrive here). This timing change is
+ * essential for VFR with b-frames but a complete nop otherwise.
+ */
+ pv->dts_next = in->start;
+ }
+ if( in->new_chap && job->chapter_markers )
+ {
+ /* chapters have to start with an IDR frame so request that this
+ frame be coded as IDR. Since there may be up to 16 frames
+ currently buffered in the encoder remember the timestamp so
+ when this frame finally pops out of the encoder we'll mark
+ its buffer as the start of a chapter. */
+ pv->pic_in.i_type = X264_TYPE_IDR;
+ if( pv->next_chap == 0 )
{
- /* Since we output at least one more frame, drop another empty
- one onto our input fifo. We'll keep doing this automatically
- until we stop getting frames out of the encoder. */
- hb_fifo_push(w->fifo_in, hb_buffer_init(0));
+ pv->next_chap = in->start;
+ pv->chap_mark = in->new_chap;
}
+ /* don't let 'work_loop' put a chapter mark on the wrong buffer */
+ in->new_chap = 0;
}
-
- if( i_nal )
+ else
{
- /* Should be way too large */
- buf = hb_buffer_init( 3 * job->width * job->height / 2 );
- buf->size = 0;
- buf->frametype = 0;
+ pv->pic_in.i_type = X264_TYPE_AUTO;
+ }
+ pv->pic_in.i_qpplus1 = 0;
- /* Get next DTS value to use */
- int64_t dts_start = pv->dts_next;
+ /* XXX this is temporary debugging code to check that the upstream
+ * modules (render & sync) have generated a continuous, self-consistent
+ * frame stream with the current frame's start time equal to the
+ * previous frame's stop time.
+ */
+ if( pv->last_stop != in->start )
+ {
+ hb_log("encx264 input continuity err: last stop %lld start %lld",
+ pv->last_stop, in->start);
+ }
+ pv->last_stop = in->stop;
- /* compute the stop time based on the original frame's duration */
- int64_t dts_stop = dts_start + get_frame_duration( pv, pic_out.i_pts );
- pv->dts_next = dts_stop;
+ // Remember info about this frame that we need to pass across
+ // the x264_encoder_encode call (since it reorders frames).
+ save_frame_info( pv, in );
- for( i = 0; i < i_nal; i++ )
- {
- int size, data;
+ /* Feed the input DTS to x264 so it can figure out proper output PTS */
+ pv->pic_in.i_pts = in->start;
- data = buf->alloc - buf->size;
- if( ( size = x264_nal_encode( buf->data + buf->size, &data,
- 1, &nal[i] ) ) < 1 )
- {
- continue;
- }
+ x264_picture_t pic_out;
+ int i_nal;
+ x264_nal_t *nal;
- if( job->mux & HB_MUX_AVI )
- {
- if( nal[i].i_ref_idc == NAL_PRIORITY_HIGHEST )
- {
- buf->frametype = HB_FRAME_KEY;
- }
- buf->size += size;
- continue;
- }
+ x264_encoder_encode( pv->x264, &nal, &i_nal, &pv->pic_in, &pic_out );
+ if ( i_nal > 0 )
+ {
+ return nal_encode( w, &pic_out, i_nal, nal );
+ }
+ return NULL;
+}
- /* H.264 in .mp4 */
- switch( buf->data[buf->size+4] & 0x1f )
- {
- case 0x7:
- case 0x8:
- /* SPS, PPS */
- break;
-
- default:
- /* H.264 in mp4 (stolen from mp4creator) */
- buf->data[buf->size+0] = ( ( size - 4 ) >> 24 ) & 0xFF;
- buf->data[buf->size+1] = ( ( size - 4 ) >> 16 ) & 0xFF;
- buf->data[buf->size+2] = ( ( size - 4 ) >> 8 ) & 0xFF;
- buf->data[buf->size+3] = ( ( size - 4 ) >> 0 ) & 0xFF;
- switch( pic_out.i_type )
- {
- /* Decide what type of frame we have. */
- case X264_TYPE_IDR:
- buf->frametype = HB_FRAME_IDR;
- /* if we have a chapter marker pending and this
- frame's presentation time stamp is at or after
- the marker's time stamp, use this as the
- chapter start. */
- if( pv->next_chap != 0 && pv->next_chap <= pic_out.i_pts )
- {
- pv->next_chap = 0;
- buf->new_chap = pv->chap_mark;
- }
- break;
- case X264_TYPE_I:
- buf->frametype = HB_FRAME_I;
- break;
- case X264_TYPE_P:
- buf->frametype = HB_FRAME_P;
- break;
- case X264_TYPE_B:
- buf->frametype = HB_FRAME_B;
- break;
- /* This is for b-pyramid, which has reference b-frames
- However, it doesn't seem to ever be used... */
- case X264_TYPE_BREF:
- buf->frametype = HB_FRAME_BREF;
- break;
- /* If it isn't the above, what type of frame is it?? */
- default:
- buf->frametype = 0;
- }
+int encx264Work( hb_work_object_t * w, hb_buffer_t ** buf_in,
+ hb_buffer_t ** buf_out )
+{
+ hb_work_private_t *pv = w->private_data;
+ hb_buffer_t *in = *buf_in;
- /* Since libx264 doesn't tell us when b-frames are
- themselves reference frames, figure it out on our own. */
- if( (buf->frametype == HB_FRAME_B) && (nal[i].i_ref_idc != NAL_PRIORITY_DISPOSABLE) )
- buf->frametype = HB_FRAME_BREF;
+ if( in->size <= 0 )
+ {
+ // EOF on input. Flush any frames still in the decoder then
+ // send the eof downstream to tell the muxer we're done.
+ x264_picture_t pic_out;
+ int i_nal;
+ x264_nal_t *nal;
+ hb_buffer_t *last_buf = NULL;
+
+ while (1)
+ {
+ x264_encoder_encode( pv->x264, &nal, &i_nal, NULL, &pic_out );
+ if ( i_nal <= 0 )
+ break;
- /* Store the output presentation time stamp
- from x264 for use by muxmp4 in off-setting
- b-frames with the CTTS atom. */
- buf->renderOffset = pic_out.i_pts - dts_start + pv->init_delay;
- if ( buf->renderOffset < 0 )
- {
- if ( dts_start - pic_out.i_pts > pv->max_delay )
- {
- pv->max_delay = dts_start - pic_out.i_pts;
- hb_log( "encx264: init_delay too small: "
- "is %lld need %lld", pv->init_delay,
- pv->max_delay );
- }
- buf->renderOffset = 0;
- }
- buf->size += size;
- }
+ hb_buffer_t *buf = nal_encode( w, &pic_out, i_nal, nal );
+ if ( last_buf == NULL )
+ *buf_out = buf;
+ else
+ last_buf->next = buf;
+ last_buf = buf;
}
- /* Send out the next dts values */
- buf->start = dts_start;
- buf->stop = dts_stop;
+ // Flushed everything - add the eof to the end of the chain.
+ if ( last_buf == NULL )
+ *buf_out = in;
+ else
+ last_buf->next = in;
+
+ *buf_in = NULL;
+ return HB_WORK_DONE;
}
+ // Not EOF - encode the packet & wrap it in a NAL
+ if ( pv->init_delay && in->stop - in->start > pv->init_delay )
+ {
+ // This frame's duration is larger than the time allotted for b-frame
+ // reordering. That means that if it's used as a reference the decoder
+ // won't be able to move it early enough to render it in correct
+ // sequence & the playback will have odd jumps & twitches. To make
+ // sure this doesn't happen we pretend this frame is multiple
+ // frames, each with duration <= init_delay. Since each of these
+ // new frames contains the same image the visual effect is identical
+ // to the original but the resulting stream can now be coded without
+ // error. We take advantage of the fact that x264 buffers frame
+ // data internally to feed the same image into the encoder multiple
+ // times, just changing its start & stop times each time.
+ int64_t orig_stop = in->stop;
+ int64_t new_stop = in->start;
+ hb_buffer_t *last_buf = NULL;
+
+ // We want to spread the new frames uniformly over the total time
+ // so that we don't end up with a very short frame at the end.
+ // In the number of pieces calculation we add in init_delay-1 to
+ // round up but not add an extra piece if the frame duration is
+ // a multiple of init_delay. The final increment of frame_dur is
+ // to restore the bits that got truncated by the divide on the
+ // previous line. If we don't do this we end up with an extra tiny
+ // frame at the end whose duration is npieces-1.
+ int64_t frame_dur = orig_stop - new_stop;
+ int64_t npieces = ( frame_dur + pv->init_delay - 1 ) / pv->init_delay;
+ frame_dur /= npieces;
+ ++frame_dur;
+
+ while ( in->start < orig_stop )
+ {
+ new_stop += frame_dur;
+ if ( new_stop > orig_stop )
+ new_stop = orig_stop;
+ in->stop = new_stop;
+ hb_buffer_t *buf = x264_encode( w, in );
+ if ( last_buf == NULL )
+ *buf_out = buf;
+ else
+ last_buf->next = buf;
+ last_buf = buf;
+ in->start = new_stop;
+ }
+ }
else
- buf = NULL;
-
- *buf_out = buf;
-
+ {
+ *buf_out = x264_encode( w, in );
+ }
return HB_WORK_OK;
}
diff --git a/libhb/encxvid.c b/libhb/encxvid.c
index 17723899d..b509baf6f 100644
--- a/libhb/encxvid.c
+++ b/libhb/encxvid.c
@@ -149,10 +149,11 @@ int encxvidWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
xvid_enc_frame_t frame;
hb_buffer_t * in = *buf_in, * buf;
- /* If this is the last empty frame, we're done */
- if(!in->data)
+ if ( in->size <= 0 )
{
- *buf_out = NULL;
+ /* EOF on input - send it downstream & say we're done */
+ *buf_out = in;
+ *buf_in = NULL;
return HB_WORK_DONE;
}
@@ -160,7 +161,6 @@ int encxvidWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
buf = hb_buffer_init( 3 * job->width * job->height / 2 );
buf->start = in->start;
buf->stop = in->stop;
- //buf->chap = in->chap;
memset( &frame, 0, sizeof( frame ) );
diff --git a/libhb/muxcommon.c b/libhb/muxcommon.c
index b3337b7bb..dcbba1583 100644
--- a/libhb/muxcommon.c
+++ b/libhb/muxcommon.c
@@ -24,7 +24,7 @@ typedef struct
hb_mux_data_t * mux_data;
uint64_t frames;
uint64_t bytes;
-
+ int eof;
} hb_track_t;
static hb_track_t * GetTrack( hb_list_t * list, hb_job_t *job )
@@ -37,34 +37,59 @@ static hb_track_t * GetTrack( hb_list_t * list, hb_job_t *job )
for( i = 0; i < hb_list_count( list ); i++ )
{
track2 = hb_list_item( list, i );
- buf = hb_fifo_see( track2->fifo );
- if( !buf )
+ if ( ! track2->eof )
{
- // XXX libmkv uses a very simple minded muxer that will fail if the
- // audio & video are out of sync. To keep them in sync we require
- // that *all* fifos have a buffer then we take the oldest.
- // Unfortunately this means we can hang in a deadlock with the
- // reader process filling the fifos. With the current libmkv
- // there's no way to avoid occasional deadlocks & we can only
- // suggest that users evolve to using mp4s.
- if ( job->mux == HB_MUX_MKV )
+ buf = hb_fifo_see( track2->fifo );
+ if( !buf )
{
- return NULL;
- }
+ // XXX the libmkv muxer will produce unplayable files if the
+ // audio & video are far out of sync. To keep them in sync we require
+ // that *all* fifos have a buffer then we take the oldest.
+ // Unfortunately this means we can hang in a deadlock with the
+ // reader process filling the fifos.
+ if ( job->mux == HB_MUX_MKV )
+ {
+ return NULL;
+ }
- // To make sure we don't camp on one fifo & prevent the others
- // from making progress we take the earliest data of all the
- // data that's currently available but we don't care if some
- // fifos don't have data.
- continue;
+ // To make sure we don't camp on one fifo & prevent the others
+ // from making progress we take the earliest data of all the
+ // data that's currently available but we don't care if some
+ // fifos don't have data.
+ continue;
+ }
+ if ( buf->size <= 0 )
+ {
+ // EOF - mark this track as done
+ buf = hb_fifo_get( track2->fifo );
+ hb_buffer_close( &buf );
+ track2->eof = 1;
+ continue;
+ }
+ if( !track || buf->start < pts )
+ {
+ track = track2;
+ pts = buf->start;
+ }
}
- if( !track || buf->start < pts )
+ }
+ return track;
+}
+
+static int AllTracksDone( hb_list_t * list )
+{
+ hb_track_t * track;
+ int i;
+
+ for( i = 0; i < hb_list_count( list ); i++ )
+ {
+ track = hb_list_item( list, i );
+ if ( track->eof == 0 )
{
- track = track2;
- pts = buf->start;
+ return 0;
}
}
- return track;
+ return 1;
}
static void MuxerFunc( void * _mux )
@@ -101,34 +126,6 @@ static void MuxerFunc( void * _mux )
}
}
- /* Wait for one buffer for each track */
- while( !*job->die && !job->done )
- {
- int ready;
-
- ready = 1;
- if( !hb_fifo_size( job->fifo_mpeg4 ) )
- {
- ready = 0;
- }
- for( i = 0; i < hb_list_count( title->list_audio ); i++ )
- {
- audio = hb_list_item( title->list_audio, i );
- if( !hb_fifo_size( audio->priv.fifo_out ) )
- {
- ready = 0;
- break;
- }
- }
-
- if( ready )
- {
- break;
- }
-
- hb_snooze( 50 );
- }
-
/* Create file, write headers */
if( job->pass == 0 || job->pass == 2 )
{
@@ -153,10 +150,15 @@ static void MuxerFunc( void * _mux )
}
int thread_sleep_interval = 50;
- while( !*job->die && !job->done )
+ while( !*job->die )
{
if( !( track = GetTrack( list, job ) ) )
{
+ if ( AllTracksDone( list ) )
+ {
+ // all our input fifos have signaled EOF
+ break;
+ }
hb_snooze( thread_sleep_interval );
continue;
}
diff --git a/libhb/muxmp4.c b/libhb/muxmp4.c
index db0c9b716..b61d579c8 100644
--- a/libhb/muxmp4.c
+++ b/libhb/muxmp4.c
@@ -285,9 +285,6 @@ static int MP4Init( hb_mux_object_t * m )
MP4SetTrackFloatProperty(m->file, mux_data->track, "tkhd.width", job->width * (width / height));
}
- /* firstAudioTrack will be used to reference the first audio track when we add a chapter track */
- MP4TrackId firstAudioTrack = 0;
-
/* add the audio tracks */
for( i = 0; i < hb_list_count( title->list_audio ); i++ )
{
@@ -344,15 +341,10 @@ static int MP4Init( hb_mux_object_t * m )
/* If we ever upgrade mpeg4ip, the line above should be replaced with the line below.*/
// MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.channels", (u_int16_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->amixdown));
- /* store a reference to the first audio track,
- so we can use it to feed the chapter text track's sample rate */
if (i == 0) {
- firstAudioTrack = mux_data->track;
-
/* Enable the first audio track */
MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_ENABLED | TRACK_IN_MOVIE));
}
-
else
/* Disable the other audio tracks so QuickTime doesn't play
them all at once. */
@@ -365,14 +357,17 @@ static int MP4Init( hb_mux_object_t * m )
if (job->chapter_markers)
{
- /* add a text track for the chapters */
- MP4TrackId textTrack;
- textTrack = MP4AddChapterTextTrack(m->file, firstAudioTrack);
+ /* add a text track for the chapters. We add the 'chap' atom to track
+ one which is usually the video track & should never be disabled.
+ The Quicktime spec says it doesn't matter which media track the
+ chap atom is on but it has to be an enabled track. */
+ MP4TrackId textTrack;
+ textTrack = MP4AddChapterTextTrack(m->file, 1);
m->chapter_track = textTrack;
m->chapter_duration = 0;
m->current_chapter = job->chapter_start;
- }
+ }
/* Add encoded-by metadata listing version and build date */
char *tool_string;
@@ -501,30 +496,21 @@ static int MP4End( hb_mux_object_t * m )
if( m->job->chapter_markers )
{
int64_t duration = m->sum_dur - m->chapter_duration;
- if ( duration <= 0 )
+ /* The final chapter can have a very short duration - if it's less
+ * than a second just skip it. */
+ if ( duration >= m->samplerate )
{
- /* The initial & final chapters can have very short durations
- * (less than the error in our total duration estimate) so
- * the duration calc above can result in a negative number.
- * when this happens give the chapter a short duration (1/3
- * of an ntsc frame time). */
- duration = 1000 * m->samplerate / 90000;
- }
-
- struct hb_text_sample_s *sample = MP4GenerateChapterSample( m, duration,
- m->current_chapter + 1 );
- if( !MP4WriteSample(m->file,
- m->chapter_track,
- sample->sample,
- sample->length,
- sample->duration,
- 0, true) )
- {
- hb_error("Failed to write to output file, disk full?");
- *job->die = 1;
+ struct hb_text_sample_s *sample = MP4GenerateChapterSample( m, duration,
+ m->current_chapter + 1 );
+ if( ! MP4WriteSample(m->file, m->chapter_track, sample->sample,
+ sample->length, sample->duration, 0, true) )
+ {
+ hb_error("Failed to write to output file, disk full?");
+ *job->die = 1;
+ }
+ free(sample);
}
- free(sample);
}
if (job->areBframes)
diff --git a/libhb/reader.c b/libhb/reader.c
index d789993f7..b06816d3d 100644
--- a/libhb/reader.c
+++ b/libhb/reader.c
@@ -69,7 +69,7 @@ static void push_buf( const hb_reader_t *r, hb_fifo_t *fifo, hb_buffer_t *buf )
while( !*r->die && !r->job->done && hb_fifo_is_full( fifo ) )
{
/*
- * Loop until the incoming fifo is reaqdy to receive
+ * Loop until the incoming fifo is ready to receive
* this buffer.
*/
hb_snooze( 50 );
@@ -326,8 +326,16 @@ static void ReaderFunc( void * _r )
}
}
- /* send an empty buffer upstream to signal we're done */
- hb_fifo_push( r->job->fifo_mpeg2, hb_buffer_init(0) );
+ /* send empty buffers upstream to video & audio decoders to signal we're done */
+ push_buf( r, r->job->fifo_mpeg2, hb_buffer_init(0) );
+
+ hb_audio_t *audio;
+ for( n = 0;
+ ( audio = hb_list_item( r->job->title->list_audio, n ) ) != NULL;
+ ++n )
+ {
+ push_buf( r, audio->priv.fifo_in, hb_buffer_init(0) );
+ }
hb_list_empty( &list );
hb_buffer_close( &ps );
diff --git a/libhb/sync.c b/libhb/sync.c
index f51e0e130..7f0ac86c4 100644
--- a/libhb/sync.c
+++ b/libhb/sync.c
@@ -23,7 +23,6 @@ typedef struct
int64_t next_start; /* start time of next output frame */
int64_t next_pts; /* start time of next input frame */
- int64_t start_silence; /* if we're inserting silence, the time we started */
int64_t first_drop; /* PTS of first 'went backwards' frame dropped */
int drop_count; /* count of 'time went backwards' drops */
@@ -72,7 +71,6 @@ struct hb_work_private_s
static void InitAudio( hb_work_object_t * w, int i );
static int SyncVideo( hb_work_object_t * w );
static void SyncAudio( hb_work_object_t * w, int i );
-static int NeedSilence( hb_work_object_t * w, hb_audio_t *, int i );
static void InsertSilence( hb_work_object_t * w, int i, int64_t d );
static void UpdateState( hb_work_object_t * w );
@@ -151,13 +149,6 @@ void syncClose( hb_work_object_t * w )
for( i = 0; i < hb_list_count( title->list_audio ); i++ )
{
- if ( pv->sync_audio[i].start_silence )
- {
- hb_log( "sync: added %d ms of silence to audio %d",
- (int)((pv->sync_audio[i].next_pts -
- pv->sync_audio[i].start_silence) / 90), i );
- }
-
audio = hb_list_item( title->list_audio, i );
if( audio->config.out.codec == HB_ACODEC_AC3 )
{
@@ -727,6 +718,13 @@ static void SyncAudio( hb_work_object_t * w, int i )
while( !hb_fifo_is_full( fifo ) && ( buf = hb_fifo_see( audio->priv.fifo_raw ) ) )
{
+ /* if the next buffer is an eof send it downstream */
+ if ( buf->size <= 0 )
+ {
+ buf = hb_fifo_get( audio->priv.fifo_raw );
+ hb_fifo_push( fifo, buf );
+ return;
+ }
if ( (int64_t)( buf->start - sync->next_pts ) < 0 )
{
// audio time went backwards.
@@ -780,43 +778,6 @@ static void SyncAudio( hb_work_object_t * w, int i )
buf = hb_fifo_get( audio->priv.fifo_raw );
OutputAudioFrame( job, audio, buf, sync, fifo, i );
}
-
- if( NeedSilence( w, audio, i ) )
- {
- InsertSilence( w, i, (90000 * AC3_SAMPLES_PER_FRAME) /
- sync->audio->config.in.samplerate );
- }
-}
-
-static int NeedSilence( hb_work_object_t * w, hb_audio_t * audio, int i )
-{
- hb_work_private_t * pv = w->private_data;
- hb_job_t * job = pv->job;
- hb_sync_audio_t * sync = &pv->sync_audio[i];
-
- if( hb_fifo_size( audio->priv.fifo_in ) ||
- hb_fifo_size( audio->priv.fifo_raw ) ||
- hb_fifo_size( audio->priv.fifo_sync ) ||
- hb_fifo_size( audio->priv.fifo_out ) )
- {
- /* We have some audio, we are fine */
- return 0;
- }
-
- /* No audio left in fifos */
-
- if( hb_thread_has_exited( job->reader ) )
- {
- /* We might miss some audio to complete encoding and muxing
- the video track */
- if ( sync->start_silence == 0 )
- {
- hb_log("sync: reader has exited, adding silence to audio %d", i);
- sync->start_silence = sync->next_pts;
- }
- return 1;
- }
- return 0;
}
static void InsertSilence( hb_work_object_t * w, int i, int64_t duration )
diff --git a/libhb/work.c b/libhb/work.c
index a6071de4b..243b6b2e7 100644
--- a/libhb/work.c
+++ b/libhb/work.c
@@ -265,7 +265,7 @@ static void do_job( hb_job_t * job, int cpu_count )
}
hb_log (" + PixelRatio: %d, width:%d, height: %d",job->pixel_ratio,job->width, job->height);
- job->fifo_mpeg2 = hb_fifo_init( 2048 );
+ job->fifo_mpeg2 = hb_fifo_init( 128 );
job->fifo_raw = hb_fifo_init( FIFO_CPU_MULT * cpu_count );
job->fifo_sync = hb_fifo_init( FIFO_CPU_MULT * cpu_count );
job->fifo_render = hb_fifo_init( FIFO_CPU_MULT * cpu_count );
@@ -585,9 +585,9 @@ static void do_job( hb_job_t * job, int cpu_count )
audio->priv.config.vorbis.language = audio->config.lang.simple;
/* set up the audio work structures */
- audio->priv.fifo_in = hb_fifo_init( 256 );
+ audio->priv.fifo_in = hb_fifo_init( 32 );
audio->priv.fifo_raw = hb_fifo_init( FIFO_CPU_MULT * cpu_count );
- audio->priv.fifo_sync = hb_fifo_init( 256 );
+ audio->priv.fifo_sync = hb_fifo_init( 32 );
audio->priv.fifo_out = hb_fifo_init( FIFO_CPU_MULT * cpu_count );
@@ -638,7 +638,6 @@ static void do_job( hb_job_t * job, int cpu_count )
job->reader = hb_reader_init( job );
hb_log( " + output: %s", job->file );
- job->muxer = hb_muxer_init( job );
job->done = 0;
@@ -658,6 +657,10 @@ static void do_job( hb_job_t * job, int cpu_count )
HB_LOW_PRIORITY );
}
+ // The muxer requires track information that's set up by the encoder
+ // init routines so we have to init the muxer last.
+ job->muxer = hb_muxer_init( job );
+
done = 0;
w = hb_list_item( job->list_work, 0 );
w->thread_sleep_interval = 50;