diff options
Diffstat (limited to 'libhb/decavcodec.c')
-rw-r--r-- | libhb/decavcodec.c | 278 |
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) { |