{
hb_job_t * job;
hb_title_t * title;
+ AVCodec * codec;
AVCodecContext * context;
AVCodecParserContext * parser;
AVFrame * frame;
* The output of this function is stored in 'pv->list', which contains a list
* of zero or more decoded packets.
*/
-static int decodeFrame( hb_work_object_t *w, packet_info_t * packet_info )
+static int decodeFrame( hb_work_private_t * pv, packet_info_t * packet_info )
{
- hb_work_private_t *pv = w->private_data;
int got_picture = 0, oldlevel = 0, ret;
AVPacket avp;
reordered_data_t * reordered;
return got_picture;
}
-static void decodeVideo( hb_work_object_t *w, hb_buffer_t * in)
-{
- hb_work_private_t *pv = w->private_data;
-
- /*
- * The following loop is a do..while because we need to handle both
- * data & the flush at the end (signaled by size=0). At the end there's
- * generally a frame in the parser & one or more frames in the decoder
- * (depending on the bframes setting).
- */
- int pos, len;
- int64_t pts = in->s.start;
- int64_t dts = in->s.renderOffset;
-
- if (in->s.new_chap > 0)
- {
- pv->new_chap = in->s.new_chap;
- pv->chap_scr = in->s.scr_sequence;
- if (in->s.start != AV_NOPTS_VALUE)
- {
- pv->chap_time = in->s.start;
- }
- else
- {
- pv->chap_time = pv->last_pts + 1;
- }
- }
- if (in->s.start != AV_NOPTS_VALUE)
- {
- pv->last_pts = in->s.start;
- }
-
- // There are a 3 scenarios that can happen here.
- // 1. The buffer contains exactly one frame of data
- // 2. The buffer contains multiple frames of data
- // 3. The buffer contains a partial frame of data
- //
- // In scenario 2, we want to be sure that the timestamps are only
- // applied to the first frame in the buffer. Additional frames
- // in the buffer will have their timestamps computed in sync.
- //
- // In scenario 3, we need to save the ancillary buffer info of an
- // unfinished frame so it can be applied when we receive the last
- // buffer of that frame.
- if (!pv->unfinished)
- {
- // New packet, and no previous data pending
- pv->packet_info.scr_sequence = in->s.scr_sequence;
- pv->packet_info.new_chap = in->s.new_chap;
- pv->packet_info.frametype = in->s.frametype;
- }
- for (pos = 0; pos < in->size; pos += len)
- {
- uint8_t * pout;
- int pout_len;
- int64_t parser_pts, parser_dts;
-
- if (pv->parser)
- {
- len = av_parser_parse2(pv->parser, pv->context, &pout, &pout_len,
- in->data + pos, in->size - pos,
- pts, dts, 0 );
- parser_pts = pv->parser->pts;
- parser_dts = pv->parser->dts;
- pts = AV_NOPTS_VALUE;
- dts = AV_NOPTS_VALUE;
- }
- else
- {
- pout = in->data;
- len = pout_len = in->size;
- parser_pts = pts;
- parser_dts = dts;
- }
-
- if (pout != NULL && pout_len > 0)
- {
- pv->packet_info.data = pout;
- pv->packet_info.size = pout_len;
- pv->packet_info.pts = parser_pts;
- pv->packet_info.dts = parser_dts;
-
- decodeFrame(w, &pv->packet_info);
- w->frame_count++;
-
- // There could have been an unfinished packet when we entered
- // decodeVideo that is now finished. The next packet is associated
- // with the input buffer, so set it's chapter and scr info.
- pv->packet_info.scr_sequence = in->s.scr_sequence;
- pv->packet_info.new_chap = in->s.new_chap;
- pv->packet_info.frametype = in->s.frametype;
- pv->unfinished = 0;
- }
- if (len > 0 && pout_len <= 0)
- {
- pv->unfinished = 1;
- }
- }
-
- /* the stuff above flushed the parser, now flush the decoder */
- if (in->s.flags & HB_BUF_FLAG_EOF)
- {
- while (decodeFrame(w, NULL))
- {
- continue;
- }
-#ifdef USE_QSV
- if (pv->qsv.decode &&
- pv->qsv.config.io_pattern == MFX_IOPATTERN_OUT_OPAQUE_MEMORY)
- {
- // flush a second time
- while (decodeFrame(w, NULL))
- {
- continue;
- }
- }
-#endif
- if (pv->list_subtitle != NULL)
- cc_send_to_decoder(pv, hb_buffer_eof_init());
- }
-}
-
static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job )
{
pv->threads = HB_FFMPEG_THREADS_AUTO;
}
- AVCodec *codec = NULL;
-
#ifdef USE_QSV
if (pv->qsv.decode)
{
- codec = avcodec_find_decoder_by_name(pv->qsv.codec_name);
+ pv->codec = avcodec_find_decoder_by_name(pv->qsv.codec_name);
}
else
#endif
{
- codec = avcodec_find_decoder(w->codec_param);
+ pv->codec = avcodec_find_decoder(w->codec_param);
}
- if ( codec == NULL )
+ if ( pv->codec == NULL )
{
hb_log( "decavcodecvInit: failed to find codec for id (%d)", w->codec_param );
return 1;
}
+ pv->context = avcodec_alloc_context3( pv->codec );
+ pv->context->workaround_bugs = FF_BUG_AUTODETECT;
+ pv->context->err_recognition = AV_EF_CRCCHECK;
+ pv->context->error_concealment = FF_EC_GUESS_MVS|FF_EC_DEBLOCK;
+
if ( pv->title->opaque_priv )
{
AVFormatContext *ic = (AVFormatContext*)pv->title->opaque_priv;
- pv->context = avcodec_alloc_context3(codec);
avcodec_parameters_to_context(pv->context,
ic->streams[pv->title->video_id]->codecpar);
- pv->context->workaround_bugs = FF_BUG_AUTODETECT;
- pv->context->err_recognition = AV_EF_CRCCHECK;
- pv->context->error_concealment = FF_EC_GUESS_MVS|FF_EC_DEBLOCK;
#ifdef USE_QSV
if (pv->qsv.decode &&
}
#endif
- if ( hb_avcodec_open( pv->context, codec, &av_opts, pv->threads ) )
+ if ( hb_avcodec_open( pv->context, pv->codec, &av_opts, pv->threads ) )
{
av_dict_free( &av_opts );
hb_log( "decavcodecvInit: avcodec_open failed" );
return 0;
}
-static int setup_extradata( hb_work_object_t *w, hb_buffer_t *in )
+static int setup_extradata( hb_work_private_t * pv )
{
- hb_work_private_t *pv = w->private_data;
-
// we can't call the avstream funcs but the read_header func in the
// AVInputFormat may set up some state in the AVContext. In particular
// vc1t_read_header allocates 'extradata' to deal with header issues
else
{
int size;
- size = pv->parser->parser->split(pv->context, in->data, in->size);
+ size = pv->parser->parser->split(pv->context, pv->packet_info.data,
+ pv->packet_info.size);
if (size > 0)
{
pv->context->extradata_size = size;
av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
if (pv->context->extradata == NULL)
return 1;
- memcpy(pv->context->extradata, in->data, size);
+ memcpy(pv->context->extradata, pv->packet_info.data, size);
return 0;
}
}
return 0;
}
-static int decavcodecvWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
- hb_buffer_t ** buf_out )
+static int decodePacket( hb_work_object_t * w )
{
- hb_work_private_t *pv = w->private_data;
- hb_buffer_t *in = *buf_in;
-
- *buf_in = NULL;
- *buf_out = NULL;
-
- // libavcodec/mpeg12dec.c requires buffers to be zero padded.
- // If not zero padded, it can get stuck in an infinite loop.
- // It's likely there are other decoders that expect the same.
- if (in->data != NULL)
- {
- memset(in->data + in->size, 0, in->alloc - in->size);
- }
-
- /* if we got an empty buffer signaling end-of-stream send it downstream */
- if (in->s.flags & HB_BUF_FLAG_EOF)
- {
- if (pv->context != NULL && pv->context->codec != NULL)
- {
- decodeVideo(w, in);
- }
- hb_buffer_list_append(&pv->list, in);
- *buf_out = hb_buffer_list_clear(&pv->list);
- return HB_WORK_DONE;
- }
+ hb_work_private_t * pv = w->private_data;
// if this is the first frame open the codec (we have to wait for the
// first frame because of M$ VC1 braindamage).
if ( !pv->video_codec_opened )
{
-
- AVCodec *codec = NULL;
-#ifdef USE_QSV
- if (pv->qsv.decode)
- {
- codec = avcodec_find_decoder_by_name(pv->qsv.codec_name);
- }
- else
-#endif
- {
- codec = avcodec_find_decoder(w->codec_param);
- }
-
- if ( codec == NULL )
- {
- hb_log( "decavcodecvWork: failed to find codec for id (%d)", w->codec_param );
- *buf_out = hb_buffer_eof_init();
- return HB_WORK_DONE;
- }
-
- if (pv->context == NULL)
- {
- pv->context = avcodec_alloc_context3( codec );
- }
pv->context->workaround_bugs = FF_BUG_AUTODETECT;
pv->context->err_recognition = AV_EF_CRCCHECK;
pv->context->error_concealment = FF_EC_GUESS_MVS|FF_EC_DEBLOCK;
- if ( setup_extradata( w, in ) )
+ if (setup_extradata(pv))
{
// we didn't find the headers needed to set up extradata.
// the codec will abort if we open it so just free the buf
// and hope we eventually get the info we need.
- hb_buffer_close( &in );
return HB_WORK_OK;
}
}
// disable threaded decoding for scan, can cause crashes
- if ( hb_avcodec_open( pv->context, codec, &av_opts, pv->threads ) )
+ if ( hb_avcodec_open( pv->context, pv->codec, &av_opts, pv->threads ) )
{
av_dict_free( &av_opts );
hb_log( "decavcodecvWork: avcodec_open failed" );
// so try again when this fails
av_freep( &pv->context->extradata );
pv->context->extradata_size = 0;
- hb_buffer_close( &in );
return HB_WORK_OK;
}
pv->context->pkt_timebase.num = pv->title->video_timebase.num;
pv->video_codec_opened = 1;
}
+ decodeFrame(pv, &pv->packet_info);
+
+ return HB_WORK_OK;
+}
+
+static int decavcodecvWork( 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;
+ int result = HB_WORK_OK;
+
+ *buf_out = NULL;
+
+ // libavcodec/mpeg12dec.c requires buffers to be zero padded.
+ // If not zero padded, it can get stuck in an infinite loop.
+ // It's likely there are other decoders that expect the same.
+ if (in->data != NULL)
+ {
+ memset(in->data + in->size, 0, in->alloc - in->size);
+ }
if (in->palette != NULL)
{
pv->palette = in->palette;
in->palette = NULL;
}
- decodeVideo(w, in);
- hb_buffer_close( &in );
+
+ /* if we got an empty buffer signaling end-of-stream send it downstream */
+ if (in->s.flags & HB_BUF_FLAG_EOF)
+ {
+ if (pv->context != NULL && pv->context->codec != NULL)
+ {
+ while (decodeFrame(pv, NULL))
+ {
+ continue;
+ }
+ }
+ hb_buffer_list_append(&pv->list, in);
+ *buf_out = hb_buffer_list_clear(&pv->list);
+ return HB_WORK_DONE;
+ }
+
+ /*
+ * The following loop is a do..while because we need to handle both
+ * data & the flush at the end (signaled by size=0). At the end there's
+ * generally a frame in the parser & one or more frames in the decoder
+ * (depending on the bframes setting).
+ */
+ int pos, len;
+ int64_t pts = in->s.start;
+ int64_t dts = in->s.renderOffset;
+
+ if (in->s.new_chap > 0)
+ {
+ pv->new_chap = in->s.new_chap;
+ pv->chap_scr = in->s.scr_sequence;
+ if (in->s.start != AV_NOPTS_VALUE)
+ {
+ pv->chap_time = in->s.start;
+ }
+ else
+ {
+ pv->chap_time = pv->last_pts + 1;
+ }
+ }
+ if (in->s.start != AV_NOPTS_VALUE)
+ {
+ pv->last_pts = in->s.start;
+ }
+
+ // There are a 3 scenarios that can happen here.
+ // 1. The buffer contains exactly one frame of data
+ // 2. The buffer contains multiple frames of data
+ // 3. The buffer contains a partial frame of data
+ //
+ // In scenario 2, we want to be sure that the timestamps are only
+ // applied to the first frame in the buffer. Additional frames
+ // in the buffer will have their timestamps computed in sync.
+ //
+ // In scenario 3, we need to save the ancillary buffer info of an
+ // unfinished frame so it can be applied when we receive the last
+ // buffer of that frame.
+ if (!pv->unfinished)
+ {
+ // New packet, and no previous data pending
+ pv->packet_info.scr_sequence = in->s.scr_sequence;
+ pv->packet_info.new_chap = in->s.new_chap;
+ pv->packet_info.frametype = in->s.frametype;
+ }
+ for (pos = 0; pos < in->size; pos += len)
+ {
+ uint8_t * pout;
+ int pout_len;
+ int64_t parser_pts, parser_dts;
+
+ if (pv->parser)
+ {
+ len = av_parser_parse2(pv->parser, pv->context, &pout, &pout_len,
+ in->data + pos, in->size - pos,
+ pts, dts, 0 );
+ parser_pts = pv->parser->pts;
+ parser_dts = pv->parser->dts;
+ pts = AV_NOPTS_VALUE;
+ dts = AV_NOPTS_VALUE;
+ }
+ else
+ {
+ pout = in->data;
+ len = pout_len = in->size;
+ parser_pts = pts;
+ parser_dts = dts;
+ }
+
+ if (pout != NULL && pout_len > 0)
+ {
+ pv->packet_info.data = pout;
+ pv->packet_info.size = pout_len;
+ pv->packet_info.pts = parser_pts;
+ pv->packet_info.dts = parser_dts;
+
+ result = decodePacket(w);
+ if (result != HB_WORK_OK)
+ {
+ break;
+ }
+ w->frame_count++;
+
+ // There could have been an unfinished packet that is now finished.
+ // The next packet is associated with the input buffer, so set
+ // it's chapter and scr info.
+ pv->packet_info.scr_sequence = in->s.scr_sequence;
+ pv->packet_info.new_chap = in->s.new_chap;
+ pv->packet_info.frametype = in->s.frametype;
+ pv->unfinished = 0;
+ }
+ if (len > 0 && pout_len <= 0)
+ {
+ pv->unfinished = 1;
+ }
+ }
*buf_out = hb_buffer_list_clear(&pv->list);
- return HB_WORK_OK;
+
+ return result;
}
+
static void compute_frame_duration( hb_work_private_t *pv )
{
double duration = 0.;
av_parser_close(pv->parser);
}
pv->parser = av_parser_init( w->codec_param );
+ pv->context = avcodec_alloc_context3( pv->codec );
}
else
{