pv->downmix = hb_downmix_init(w->audio->config.in.channel_layout,
w->audio->config.out.mixdown);
hb_downmix_set_chan_map( pv->downmix, &hb_smpte_chan_map, &hb_qt_chan_map );
- if ( w->audio->config.out.codec == HB_ACODEC_LAME )
- hb_downmix_adjust_level( pv->downmix );
}
return 0;
return avcodec_default_get_buffer( context, frame );
}
+static int reget_frame_buf( AVCodecContext *context, AVFrame *frame )
+{
+ hb_work_private_t *pv = context->opaque;
+ frame->pts = pv->pts;
+ pv->pts = -1;
+ return avcodec_default_reget_buffer( context, frame );
+}
+
static void log_chapter( hb_work_private_t *pv, int chap_num, int64_t pts )
{
hb_chapter_t *c = hb_list_item( pv->job->title->list_chapter, chap_num - 1 );
}
}
-static int decodeFrame( hb_work_private_t *pv, uint8_t *data, int size )
+/*
+ * Decodes a video frame from the specified raw packet data ('data', 'size', 'sequence').
+ * The output of this function is stored in 'pv->list', which contains a list
+ * of zero or more decoded packets.
+ *
+ * The returned packets are guaranteed to have their timestamps in the correct order,
+ * even if the original packets decoded by libavcodec have misordered timestamps,
+ * due to the use of 'packed B-frames'.
+ *
+ * Internally the set of decoded packets may be buffered in 'pv->delayq'
+ * until enough packets have been decoded so that the timestamps can be
+ * correctly rewritten, if this is necessary.
+ */
+static int decodeFrame( hb_work_private_t *pv, uint8_t *data, int size, int sequence )
{
int got_picture, oldlevel = 0;
AVFrame frame;
{
buf = copy_frame( pv, &frame );
buf->start = pts;
+ buf->sequence = sequence;
hb_list_add( pv->list, buf );
++pv->nframes;
return got_picture;
}
// add the new frame to the delayq & push its timestamp on the heap
- pv->delayq[slot] = copy_frame( pv, &frame );
+ buf = copy_frame( pv, &frame );
+ buf->sequence = sequence;
+ pv->delayq[slot] = buf;
heap_push( &pv->pts_heap, pts );
++pv->nframes;
return got_picture;
}
-static void decodeVideo( hb_work_private_t *pv, uint8_t *data, int size,
+static void decodeVideo( hb_work_private_t *pv, uint8_t *data, int size, int sequence,
int64_t pts, int64_t dts )
{
/*
if ( pout_len > 0 )
{
pv->pts = pv->parser->pts;
- decodeFrame( pv, pout, pout_len );
+ decodeFrame( pv, pout, pout_len, sequence );
}
} while ( pos < size );
/* the stuff above flushed the parser, now flush the decoder */
if ( size <= 0 )
{
- while ( decodeFrame( pv, NULL, 0 ) )
+ while ( decodeFrame( pv, NULL, 0, sequence ) )
{
}
flushDelayQueue( pv );
}
}
+/*
+ * Removes all packets from 'pv->list', links them together into
+ * a linked-list, and returns the first packet in the list.
+ */
static hb_buffer_t *link_buf_list( hb_work_private_t *pv )
{
hb_buffer_t *head = hb_list_item( pv->list, 0 );
/* we have to wrap ffmpeg's get_buffer to be able to set the pts (?!) */
pv->context->opaque = pv;
pv->context->get_buffer = get_frame_buf;
+ pv->context->reget_buffer = reget_frame_buf;
return 0;
}
/* if we got an empty buffer signaling end-of-stream send it downstream */
if ( in->size == 0 )
{
- decodeVideo( pv, in->data, in->size, pts, dts );
+ decodeVideo( pv, in->data, in->size, in->sequence, pts, dts );
hb_list_add( pv->list, in );
*buf_out = link_buf_list( pv );
return HB_WORK_DONE;
pv->new_chap = in->new_chap;
pv->chap_time = pts >= 0? pts : pv->pts_next;
}
- decodeVideo( pv, in->data, in->size, pts, dts );
+ decodeVideo( pv, in->data, in->size, in->sequence, pts, dts );
hb_buffer_close( &in );
*buf_out = link_buf_list( pv );
return HB_WORK_OK;
// Because the time bases are so screwed up, we only take values
// in the range 8fps - 64fps.
AVRational tb;
- if ( st->time_base.num * 64 > st->time_base.den &&
- st->time_base.den > st->time_base.num * 8 )
+ if ( st->avg_frame_rate.den * 64 > st->avg_frame_rate.num &&
+ st->avg_frame_rate.num > st->avg_frame_rate.den * 8 )
+ {
+ tb.num = st->avg_frame_rate.den;
+ tb.den = st->avg_frame_rate.num;
+ }
+ else if ( st->time_base.num * 64 > st->time_base.den &&
+ st->time_base.den > st->time_base.num * 8 )
{
tb = st->time_base;
}
// we have to wrap ffmpeg's get_buffer to be able to set the pts (?!)
pv->context->opaque = pv;
pv->context->get_buffer = get_frame_buf;
+ pv->context->reget_buffer = reget_frame_buf;
// avi, mkv and possibly mp4 containers can contain the M$ VFW packed
// b-frames abortion that messes up frame ordering and timestamps.
pv->downmix = hb_downmix_init(w->audio->config.in.channel_layout,
w->audio->config.out.mixdown);
hb_downmix_set_chan_map( pv->downmix, &hb_smpte_chan_map, &hb_qt_chan_map );
- if ( w->audio->config.out.codec == HB_ACODEC_LAME )
- hb_downmix_adjust_level( pv->downmix );
}
return 0;
if ( in->size == 0 )
{
/* flush any frames left in the decoder */
- while ( pv->context && decodeFrame( pv, NULL, 0 ) )
+ while ( pv->context && decodeFrame( pv, NULL, 0, in->sequence ) )
{
}
flushDelayQueue( pv );
pv->chap_time = pts >= 0? pts : pv->pts_next;
}
prepare_ffmpeg_buffer( in );
- decodeFrame( pv, in->data, in->size );
+ decodeFrame( pv, in->data, in->size, in->sequence );
hb_buffer_close( &in );
*buf_out = link_buf_list( pv );
return HB_WORK_OK;
{
AVCodecContext *context = pv->context;
int pos = 0;
+ int loop_limit = 256;
while ( pos < size )
{
int out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
int nsamples;
int len = avcodec_decode_audio3( context, buffer, &out_size, &avp );
- if ( len <= 0 )
+ if ( len < 0 )
{
return;
}
+ if ( len == 0 )
+ {
+ if ( !(loop_limit--) )
+ return;
+ }
+ else
+ loop_limit = 256;
+
pos += len;
if( out_size > 0 )
{