summaryrefslogtreecommitdiffstats
path: root/libhb/decavcodec.c
diff options
context:
space:
mode:
Diffstat (limited to 'libhb/decavcodec.c')
-rw-r--r--libhb/decavcodec.c278
1 files changed, 217 insertions, 61 deletions
diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c
index 8f88267b5..f3d9c78cd 100644
--- a/libhb/decavcodec.c
+++ b/libhb/decavcodec.c
@@ -86,6 +86,7 @@ struct hb_work_private_s
hb_title_t *title;
AVCodecContext *context;
AVCodecParserContext *parser;
+ AVFrame *frame;
int threads;
int video_codec_opened;
hb_list_t *list;
@@ -129,6 +130,8 @@ struct hb_work_private_s
#endif
} qsv;
#endif
+
+ hb_list_t * list_subtitle;
};
#ifdef USE_QSV_PTS_WORKAROUND
@@ -308,7 +311,6 @@ static int decavcodecaInit( hb_work_object_t * w, hb_job_t * job )
{
// libavcodec can't decode TrueHD Mono (bug #356)
// work around it by requesting Stereo and downmixing
- pv->context->request_channels = 2;
pv->context->request_channel_layout = AV_CH_LAYOUT_STEREO;
break;
}
@@ -327,11 +329,24 @@ static int decavcodecaInit( hb_work_object_t * w, hb_job_t * job )
}
}
- if (hb_avcodec_open(pv->context, codec, NULL, 0))
+ // Set decoder opts...
+ AVDictionary * av_opts = NULL;
+ av_dict_set( &av_opts, "refcounted_frames", "1", 0 );
+
+ if (hb_avcodec_open(pv->context, codec, &av_opts, 0))
{
+ av_dict_free( &av_opts );
hb_log("decavcodecaInit: avcodec_open failed");
return 1;
}
+ av_dict_free( &av_opts );
+
+ pv->frame = av_frame_alloc();
+ if (pv->frame == NULL)
+ {
+ hb_log("decavcodecaInit: av_frame_alloc failed");
+ return 1;
+ }
return 0;
}
@@ -357,6 +372,7 @@ static void closePrivData( hb_work_private_t ** ppv )
pv->context->codec->name, pv->nframes, pv->decode_errors,
pv->ndrops );
}
+ av_frame_free(&pv->frame);
if ( pv->sws_context )
{
sws_freeContext( pv->sws_context );
@@ -405,7 +421,7 @@ static void closePrivData( hb_work_private_t ** ppv )
HB_OCL_BUF_FREE(hb_ocl, pv->dxva2->cl_mem_nv12);
}
hb_va_close(pv->dxva2);
- }
+ }
#endif
#ifdef USE_QSV_PTS_WORKAROUND
@@ -430,7 +446,7 @@ static void closePrivData( hb_work_private_t ** ppv )
static void decavcodecClose( hb_work_object_t * w )
{
hb_work_private_t * pv = w->private_data;
-#ifdef USE_HWD
+#ifdef USE_HWD
if( pv->dst_frame ) free( pv->dst_frame );
#endif
if ( pv )
@@ -595,30 +611,28 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf,
context->channel_layout == AV_CH_LAYOUT_MONO)
{
truehd_mono = 1;
- context->request_channels = 2;
context->request_channel_layout = AV_CH_LAYOUT_STEREO;
}
else
{
- context->request_channels = 0;
context->request_channel_layout = 0;
}
if (pbuffer_size > 0)
{
int got_frame;
- AVFrame frame = { { 0 } };
+ AVFrame *frame = av_frame_alloc();
AVPacket avp;
av_init_packet(&avp);
avp.data = pbuffer;
avp.size = pbuffer_size;
- len = avcodec_decode_audio4(context, &frame, &got_frame, &avp);
+ len = avcodec_decode_audio4(context, frame, &got_frame, &avp);
if (len > 0 && context->sample_rate > 0)
{
info->rate_base = 1;
info->rate = context->sample_rate;
- info->samples_per_frame = frame.nb_samples;
+ info->samples_per_frame = frame->nb_samples;
int bps = av_get_bits_per_sample(context->codec_id);
if (bps > 0 && context->channels > 0)
@@ -692,7 +706,7 @@ static uint8_t *copy_plane( uint8_t *dst, uint8_t* src, int dstride, int sstride
// copy one video frame into an HB buf. If the frame isn't in our color space
// or at least one of its dimensions is odd, use sws_scale to convert/rescale it.
// Otherwise just copy the bits.
-static hb_buffer_t *copy_frame( hb_work_private_t *pv, AVFrame *frame )
+static hb_buffer_t *copy_frame( hb_work_private_t *pv )
{
AVCodecContext *context = pv->context;
int w, h;
@@ -724,7 +738,7 @@ static hb_buffer_t *copy_frame( hb_work_private_t *pv, AVFrame *frame )
{
pv->dst_frame = malloc( ww * hh * 3 / 2 );
}
- if( hb_va_extract( pv->dxva2, pv->dst_frame, frame, pv->job->width, pv->job->height, pv->job->title->crop, pv->opencl_scale, pv->job->use_opencl, pv->job->use_decomb, pv->job->use_detelecine ) == HB_WORK_ERROR )
+ if( hb_va_extract( pv->dxva2, pv->dst_frame, pv->frame, pv->job->width, pv->job->height, pv->job->title->crop, pv->opencl_scale, pv->job->use_opencl, pv->job->use_decomb, pv->job->use_detelecine ) == HB_WORK_ERROR )
{
hb_log( "hb_va_Extract failed!!!!!!" );
}
@@ -752,7 +766,7 @@ static hb_buffer_t *copy_frame( hb_work_private_t *pv, AVFrame *frame )
if (pv->qsv.decode &&
pv->qsv.config.io_pattern == MFX_IOPATTERN_OUT_OPAQUE_MEMORY)
{
- buf->qsv_details.qsv_atom = frame->data[2];
+ buf->qsv_details.qsv_atom = pv->frame->data[2];
return buf;
}
#endif
@@ -783,7 +797,8 @@ static hb_buffer_t *copy_frame( hb_work_private_t *pv, AVFrame *frame )
pv->sws_pix_fmt = context->pix_fmt;
}
sws_scale(pv->sws_context,
- (const uint8_t* const *)frame->data, frame->linesize,
+ (const uint8_t* const *)pv->frame->data,
+ pv->frame->linesize,
0, context->height, dstpic.data, dstpic.linesize);
}
else
@@ -791,15 +806,15 @@ static hb_buffer_t *copy_frame( hb_work_private_t *pv, AVFrame *frame )
w = buf->plane[0].stride;
h = buf->plane[0].height;
dst = buf->plane[0].data;
- copy_plane( dst, frame->data[0], w, frame->linesize[0], h );
+ copy_plane( dst, pv->frame->data[0], w, pv->frame->linesize[0], h );
w = buf->plane[1].stride;
h = buf->plane[1].height;
dst = buf->plane[1].data;
- copy_plane( dst, frame->data[1], w, frame->linesize[1], h );
+ copy_plane( dst, pv->frame->data[1], w, pv->frame->linesize[1], h );
w = buf->plane[2].stride;
h = buf->plane[2].height;
dst = buf->plane[2].data;
- copy_plane( dst, frame->data[2], w, frame->linesize[2], h );
+ copy_plane( dst, pv->frame->data[2], w, pv->frame->linesize[2], h );
}
return buf;
}
@@ -956,6 +971,67 @@ static void checkCadence( int * cadence, uint16_t flags, int64_t start )
hb_log("%fs: Film -> Video", (float)start / 90000);
}
+// send cc_buf to the CC decoder(s)
+static void cc_send_to_decoder(hb_work_private_t *pv, hb_buffer_t *buf)
+{
+ if (buf == NULL)
+ return;
+
+ // if there's more than one decoder for the captions send a copy
+ // of the buffer to all.
+ hb_subtitle_t *subtitle;
+ int ii = 0, n = hb_list_count(pv->list_subtitle);
+ while (--n > 0)
+ {
+ // make a copy of the buf then forward it to the decoder
+ hb_buffer_t *cpy = hb_buffer_dup(buf);
+
+ subtitle = hb_list_item(pv->list_subtitle, ii++);
+ hb_fifo_push(subtitle->fifo_in, cpy);
+ }
+ subtitle = hb_list_item(pv->list_subtitle, ii);
+ hb_fifo_push( subtitle->fifo_in, buf );
+}
+
+static hb_buffer_t * cc_fill_buffer(hb_work_private_t *pv, uint8_t *cc, int size, int64_t pts)
+{
+ int cc_count[4] = {0,};
+ int ii;
+ hb_buffer_t *buf = NULL;
+
+ for (ii = 0; ii < size; ii += 3)
+ {
+ if ((cc[ii] & 0x04) == 0) // not valid
+ continue;
+ if ((cc[ii+1] & 0x7f) == 0 && (cc[ii+2] & 0x7f) == 0) // stuffing
+ continue;
+ int type = cc[ii] & 0x03;
+ cc_count[type]++;
+ }
+
+ // Only handles CC1 for now.
+ if (cc_count[0] > 0)
+ {
+ buf = hb_buffer_init(cc_count[0] * 2);
+ buf->s.start = pts;
+ int jj = 0;
+ for (ii = 0; ii < size; ii += 3)
+ {
+ if ((cc[ii] & 0x04) == 0) // not valid
+ continue;
+ if ((cc[ii+1] & 0x7f) == 0 && (cc[ii+2] & 0x7f) == 0) // stuffing
+ continue;
+ int type = cc[ii] & 0x03;
+ if (type == 0)
+ {
+ buf->data[jj++] = cc[ii+1];
+ buf->data[jj++] = cc[ii+2];
+ }
+ }
+ }
+ return buf;
+}
+
/*
* Decodes a video frame from the specified raw packet data
* ('data', 'size', 'sequence').
@@ -974,7 +1050,6 @@ static int decodeFrame( hb_work_object_t *w, uint8_t *data, int size, int sequen
{
hb_work_private_t *pv = w->private_data;
int got_picture, oldlevel = 0;
- AVFrame frame = { { 0 } };
AVPacket avp;
if ( global_verbosity_level <= 1 )
@@ -991,7 +1066,7 @@ static int decodeFrame( hb_work_object_t *w, uint8_t *data, int size, int sequen
/*
* libav avcodec_decode_video2() needs AVPacket flagged with AV_PKT_FLAG_KEY
* for some codecs. For example, sequence of PNG in a mov container.
- */
+ */
if ( frametype & HB_FRAME_KEY )
{
avp.flags |= AV_PKT_FLAG_KEY;
@@ -1011,7 +1086,7 @@ static int decodeFrame( hb_work_object_t *w, uint8_t *data, int size, int sequen
}
#endif
- if ( avcodec_decode_video2( pv->context, &frame, &got_picture, &avp ) < 0 )
+ if ( avcodec_decode_video2( pv->context, pv->frame, &got_picture, &avp ) < 0 )
{
++pv->decode_errors;
}
@@ -1029,7 +1104,7 @@ static int decodeFrame( hb_work_object_t *w, uint8_t *data, int size, int sequen
if (pv->qsv.decode && got_picture)
{
// we got a decoded frame, restore the lowest available PTS
- frame.pkt_pts = hb_av_pop_next_pts(pv->qsv.pts_list);
+ pv->frame->pkt_pts = hb_av_pop_next_pts(pv->qsv.pts_list);
}
#endif
@@ -1037,22 +1112,6 @@ static int decodeFrame( hb_work_object_t *w, uint8_t *data, int size, int sequen
{
av_log_set_level( oldlevel );
}
- if( got_picture && pv->wait_for_keyframe > 0 )
- {
- // Libav is inconsistant about how it flags keyframes. For many
- // codecs it simply sets frame.key_frame. But for others, it only
- // sets frame.pict_type. And for yet others neither gets set at all
- // (qtrle).
- int key = frame.key_frame || (w->codec_param != AV_CODEC_ID_H264 &&
- (frame.pict_type == 0 ||
- frame.pict_type == AV_PICTURE_TYPE_I));
- if( !key )
- {
- pv->wait_for_keyframe--;
- return 0;
- }
- pv->wait_for_keyframe = 0;
- }
if( got_picture )
{
uint16_t flags = 0;
@@ -1075,9 +1134,9 @@ static int decodeFrame( hb_work_object_t *w, uint8_t *data, int size, int sequen
double pts;
double frame_dur = pv->duration;
- if ( frame.repeat_pict )
+ if ( pv->frame->repeat_pict )
{
- frame_dur += frame.repeat_pict * pv->field_duration;
+ frame_dur += pv->frame->repeat_pict * pv->field_duration;
}
#ifdef USE_HWD
if( pv->dxva2 && pv->dxva2->do_job == HB_WORK_OK )
@@ -1085,49 +1144,107 @@ static int decodeFrame( hb_work_object_t *w, uint8_t *data, int size, int sequen
if( avp.pts>0 )
{
if( pv->dxva2->input_pts[0] != 0 && pv->dxva2->input_pts[1] == 0 )
- frame.pkt_pts = pv->dxva2->input_pts[0];
+ pv->frame->pkt_pts = pv->dxva2->input_pts[0];
else
- frame.pkt_pts = pv->dxva2->input_pts[0]<pv->dxva2->input_pts[1] ? pv->dxva2->input_pts[0] : pv->dxva2->input_pts[1];
+ pv->frame->pkt_pts = pv->dxva2->input_pts[0]<pv->dxva2->input_pts[1] ? pv->dxva2->input_pts[0] : pv->dxva2->input_pts[1];
}
}
#endif
// If there was no pts for this frame, assume constant frame rate
// video & estimate the next frame time from the last & duration.
- if (frame.pkt_pts == AV_NOPTS_VALUE || hb_gui_use_hwd_flag == 1)
+ if (pv->frame->pkt_pts == AV_NOPTS_VALUE || hb_gui_use_hwd_flag == 1)
{
pts = pv->pts_next;
}
else
{
- pts = frame.pkt_pts;
+ pts = pv->frame->pkt_pts;
}
pv->pts_next = pts + frame_dur;
- if ( frame.top_field_first )
+ if ( pv->frame->top_field_first )
{
flags |= PIC_FLAG_TOP_FIELD_FIRST;
}
- if ( !frame.interlaced_frame )
+ if ( !pv->frame->interlaced_frame )
{
flags |= PIC_FLAG_PROGRESSIVE_FRAME;
}
- if ( frame.repeat_pict == 1 )
+ if ( pv->frame->repeat_pict == 1 )
{
flags |= PIC_FLAG_REPEAT_FIRST_FIELD;
}
- if ( frame.repeat_pict == 2 )
+ if ( pv->frame->repeat_pict == 2 )
{
flags |= PIC_FLAG_REPEAT_FRAME;
}
+ // Check for CC data
+ AVFrameSideData *sd;
+ sd = av_frame_get_side_data(pv->frame, AV_FRAME_DATA_A53_CC);
+ if (sd != NULL)
+ {
+ if (!pv->job && pv->title && sd->size > 0)
+ {
+ hb_subtitle_t *subtitle;
+ int i = 0;
+
+ while ((subtitle = hb_list_item(pv->title->list_subtitle, i++)))
+ {
+ /*
+ * Let's call them 608 subs for now even if they aren't,
+ * since they are the only types we grok.
+ */
+ if (subtitle->source == CC608SUB)
+ {
+ break;
+ }
+ }
+ if (subtitle == NULL)
+ {
+ subtitle = calloc(sizeof( hb_subtitle_t ), 1);
+ subtitle->track = 0;
+ subtitle->id = 0;
+ subtitle->format = TEXTSUB;
+ subtitle->source = CC608SUB;
+ subtitle->config.dest = PASSTHRUSUB;
+ subtitle->codec = WORK_DECCC608;
+ subtitle->type = 5;
+ snprintf(subtitle->lang, sizeof( subtitle->lang ),
+ "Closed Captions");
+ /*
+ * The language of the subtitles will be the same as the
+ * first audio track, i.e. the same as the video.
+ */
+ hb_audio_t *audio = hb_list_item(pv->title->list_audio, 0);
+ if (audio != NULL)
+ {
+ snprintf(subtitle->iso639_2, sizeof(subtitle->iso639_2),
+ "%s", audio->config.lang.iso639_2);
+ } else {
+ snprintf(subtitle->iso639_2, sizeof(subtitle->iso639_2),
+ "und");
+ }
+ hb_list_add(pv->title->list_subtitle, subtitle);
+ }
+ }
+ if (pv->list_subtitle != NULL && sd->size > 0)
+ {
+ hb_buffer_t *cc_buf;
+ cc_buf = cc_fill_buffer(pv, sd->data, sd->size, pts);
+ cc_send_to_decoder(pv, cc_buf);
+ }
+ }
+
hb_buffer_t *buf;
// if we're doing a scan or this content couldn't have been broken
// by Microsoft we don't worry about timestamp reordering
if ( ! pv->job || ! pv->brokenByMicrosoft )
{
- buf = copy_frame( pv, &frame );
+ buf = copy_frame( pv );
+ av_frame_unref(pv->frame);
buf->s.start = pts;
buf->sequence = sequence;
@@ -1194,7 +1311,8 @@ static int decodeFrame( hb_work_object_t *w, uint8_t *data, int size, int sequen
}
// add the new frame to the delayq & push its timestamp on the heap
- buf = copy_frame( pv, &frame );
+ buf = copy_frame( pv );
+ av_frame_unref(pv->frame);
buf->sequence = sequence;
/* Store picture flags for later use by filters */
buf->s.flags = flags;
@@ -1261,6 +1379,8 @@ static void decodeVideo( hb_work_object_t *w, uint8_t *data, int size, int seque
}
#endif
flushDelayQueue(pv);
+ if (pv->list_subtitle != NULL)
+ cc_send_to_decoder(pv, hb_buffer_init(0));
}
}
@@ -1391,11 +1511,18 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job )
}
#endif
- if ( hb_avcodec_open( pv->context, codec, NULL, pv->threads ) )
+ // Set encoder opts...
+ AVDictionary * av_opts = NULL;
+ av_dict_set( &av_opts, "refcounted_frames", "1", 0 );
+
+ if ( hb_avcodec_open( pv->context, codec, &av_opts, pv->threads ) )
{
+ av_dict_free( &av_opts );
hb_log( "decavcodecvInit: avcodec_open failed" );
return 1;
}
+ av_dict_free( &av_opts );
+
pv->video_codec_opened = 1;
// avi, mkv and possibly mp4 containers can contain the M$ VFW packed
// b-frames abortion that messes up frame ordering and timestamps.
@@ -1413,6 +1540,35 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job )
pv->context->err_recognition = AV_EF_CRCCHECK;
pv->context->error_concealment = FF_EC_GUESS_MVS|FF_EC_DEBLOCK;
}
+
+ pv->frame = av_frame_alloc();
+ if (pv->frame == NULL)
+ {
+ hb_log("decavcodecvInit: av_frame_alloc failed");
+ return 1;
+ }
+
+ /*
+ * If not scanning, then are we supposed to extract Closed Captions
+ * and send them to the decoder?
+ */
+ if (job != NULL && hb_list_count(job->list_subtitle) > 0)
+ {
+ hb_subtitle_t *subtitle;
+ int i = 0;
+
+ while ((subtitle = hb_list_item(job->list_subtitle, i++)) != NULL)
+ {
+ if (subtitle->source == CC608SUB)
+ {
+ if (pv->list_subtitle == NULL)
+ {
+ pv->list_subtitle = hb_list_init();
+ }
+ hb_list_add(pv->list_subtitle, subtitle);
+ }
+ }
+ }
return 0;
}
@@ -1572,13 +1728,18 @@ static int decavcodecvWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
}
#endif
+ AVDictionary * av_opts = NULL;
+ av_dict_set( &av_opts, "refcounted_frames", "1", 0 );
+
// disable threaded decoding for scan, can cause crashes
- if ( hb_avcodec_open( pv->context, codec, NULL, pv->threads ) )
+ if ( hb_avcodec_open( pv->context, codec, &av_opts, pv->threads ) )
{
+ av_dict_free( &av_opts );
hb_log( "decavcodecvWork: avcodec_open failed" );
*buf_out = hb_buffer_init( 0 );;
return HB_WORK_DONE;
}
+ av_dict_free( &av_opts );
pv->video_codec_opened = 1;
}
@@ -1653,12 +1814,6 @@ static void compute_frame_duration( hb_work_private_t *pv )
tb = &(st->time_base);
duration = (double)tb->num / (double)tb->den;
}
- else if ( st->r_frame_rate.den * 64L > st->r_frame_rate.num &&
- st->r_frame_rate.num > st->r_frame_rate.den * 8L )
- {
- tb = &(st->r_frame_rate);
- duration = (double)tb->den / (double)tb->num;
- }
}
if ( !duration &&
pv->context->time_base.num * max_fps > pv->context->time_base.den &&
@@ -1876,7 +2031,6 @@ static void decodeAudio(hb_audio_t *audio, hb_work_private_t *pv, uint8_t *data,
while (pos < size)
{
int got_frame;
- AVFrame frame = { { 0 } };
AVPacket avp;
av_init_packet(&avp);
@@ -1885,7 +2039,7 @@ static void decodeAudio(hb_audio_t *audio, hb_work_private_t *pv, uint8_t *data,
avp.pts = pv->pts_next;
avp.dts = AV_NOPTS_VALUE;
- int len = avcodec_decode_audio4(context, &frame, &got_frame, &avp);
+ int len = avcodec_decode_audio4(context, pv->frame, &got_frame, &avp);
if ((len < 0) || (!got_frame && !(loop_limit--)))
{
return;
@@ -1915,7 +2069,7 @@ static void decodeAudio(hb_audio_t *audio, hb_work_private_t *pv, uint8_t *data,
if (got_frame)
{
hb_buffer_t *out;
- double duration = frame.nb_samples * pv->duration;
+ double duration = pv->frame->nb_samples * pv->duration;
double pts_next = pv->pts_next + duration;
if (audio->config.out.codec & HB_ACODEC_PASS_FLAG)
@@ -1936,11 +2090,13 @@ static void decodeAudio(hb_audio_t *audio, hb_work_private_t *pv, uint8_t *data,
if (hb_audio_resample_update(pv->resample))
{
hb_log("decavcodec: hb_audio_resample_update() failed");
+ av_frame_unref(pv->frame);
return;
}
- out = hb_audio_resample(pv->resample, frame.extended_data,
- frame.nb_samples);
+ out = hb_audio_resample(pv->resample, pv->frame->extended_data,
+ pv->frame->nb_samples);
}
+ av_frame_unref(pv->frame);
if (out != NULL)
{