X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fcrystalhd.c;h=83bc8bf36410715c43c25f1c5f673f8b62a4d12c;hb=b5325c6711a6789e6219f6392fd9158cb2c0fcd7;hp=630d02b6f55c44a83619f9a087f9cd102a111b10;hpb=9142b04bba45c27a69ac8baec088357070614674;p=ffmpeg diff --git a/libavcodec/crystalhd.c b/libavcodec/crystalhd.c index 630d02b6f55..83bc8bf3641 100644 --- a/libavcodec/crystalhd.c +++ b/libavcodec/crystalhd.c @@ -55,6 +55,7 @@ #include #include "avcodec.h" +#include "decode.h" #include "internal.h" #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" @@ -91,15 +92,7 @@ typedef struct { AVCodecContext *avctx; HANDLE dev; - uint8_t *orig_extradata; - uint32_t orig_extradata_size; - - AVBSFContext *bsfc; - uint8_t is_70012; - uint8_t *sps_pps_buf; - uint32_t sps_pps_size; - uint8_t is_nal; uint8_t need_second_field; uint8_t draining; @@ -108,7 +101,6 @@ typedef struct { /* Options */ uint32_t sWidth; - uint8_t bframe_bug; } CHDContext; static const AVOption options[] = { @@ -139,7 +131,7 @@ static inline BC_MEDIA_SUBTYPE id2subtype(CHDContext *priv, enum AVCodecID id) case AV_CODEC_ID_WMV3: return BC_MSUBTYPE_WMV3; case AV_CODEC_ID_H264: - return priv->is_nal ? BC_MSUBTYPE_AVC1 : BC_MSUBTYPE_H264; + return BC_MSUBTYPE_H264; default: return BC_MSUBTYPE_INVALID; } @@ -294,25 +286,6 @@ static av_cold int uninit(AVCodecContext *avctx) DtsCloseDecoder(device); DtsDeviceClose(device); - /* - * Restore original extradata, so that if the decoder is - * reinitialised, the bitstream detection and filtering - * will work as expected. - */ - if (priv->orig_extradata) { - av_free(avctx->extradata); - avctx->extradata = priv->orig_extradata; - avctx->extradata_size = priv->orig_extradata_size; - priv->orig_extradata = NULL; - priv->orig_extradata_size = 0; - } - - if (priv->bsfc) { - av_bsf_free(&priv->bsfc); - } - - av_freep(&priv->sps_pps_buf); - if (priv->head) { OpaqueList *node = priv->head; while (node) { @@ -325,60 +298,9 @@ static av_cold int uninit(AVCodecContext *avctx) return 0; } - -static av_cold int init_bsf(AVCodecContext *avctx, const char *bsf_name) -{ - CHDContext *priv = avctx->priv_data; - const AVBitStreamFilter *bsf; - int avret; - void *extradata = NULL; - size_t size = 0; - - bsf = av_bsf_get_by_name(bsf_name); - if (!bsf) { - av_log(avctx, AV_LOG_ERROR, - "Cannot open the %s BSF!\n", bsf_name); - return AVERROR_BSF_NOT_FOUND; - } - - avret = av_bsf_alloc(bsf, &priv->bsfc); - if (avret != 0) { - return avret; - } - - avret = avcodec_parameters_from_context(priv->bsfc->par_in, avctx); - if (avret != 0) { - return avret; - } - - avret = av_bsf_init(priv->bsfc); - if (avret != 0) { - return avret; - } - - /* Back up the extradata so it can be restored at close time. */ - priv->orig_extradata = avctx->extradata; - priv->orig_extradata_size = avctx->extradata_size; - - size = priv->bsfc->par_out->extradata_size; - extradata = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!extradata) { - av_log(avctx, AV_LOG_ERROR, - "Failed to allocate copy of extradata\n"); - return AVERROR(ENOMEM); - } - memcpy(extradata, priv->bsfc->par_out->extradata, size); - - avctx->extradata = extradata; - avctx->extradata_size = size; - - return 0; -} - static av_cold int init(AVCodecContext *avctx) { CHDContext* priv; - int avret; BC_STATUS ret; BC_INFO_CRYSTAL version; BC_INPUT_FORMAT format = { @@ -406,21 +328,10 @@ static av_cold int init(AVCodecContext *avctx) /* Initialize the library */ priv = avctx->priv_data; priv->avctx = avctx; - priv->is_nal = avctx->extradata_size > 0 && *(avctx->extradata) == 1; priv->draining = 0; subtype = id2subtype(priv, avctx->codec->id); switch (subtype) { - case BC_MSUBTYPE_AVC1: - avret = init_bsf(avctx, "h264_mp4toannexb"); - if (avret != 0) { - return avret; - } - subtype = BC_MSUBTYPE_H264; - format.startCodeSz = 4; - format.pMetaData = avctx->extradata; - format.metaDataSz = avctx->extradata_size; - break; case BC_MSUBTYPE_H264: format.startCodeSz = 4; // Fall-through @@ -625,17 +536,16 @@ static inline CopyRet copy_frame(AVCodecContext *avctx, if (interlaced) frame->top_field_first = !bottom_first; - if (pkt_pts != AV_NOPTS_VALUE) { - frame->pts = pkt_pts; + frame->pts = pkt_pts; #if FF_API_PKT_PTS FF_DISABLE_DEPRECATION_WARNINGS - frame->pkt_pts = pkt_pts; + frame->pkt_pts = pkt_pts; FF_ENABLE_DEPRECATION_WARNINGS #endif - } - av_frame_set_pkt_pos(frame, -1); - av_frame_set_pkt_duration(frame, 0); - av_frame_set_pkt_size(frame, -1); + + frame->pkt_pos = -1; + frame->pkt_duration = 0; + frame->pkt_size = -1; if (!priv->need_second_field) { *got_frame = 1; @@ -720,16 +630,6 @@ static inline CopyRet receive_frame(AVCodecContext *avctx, } else if (ret == BC_STS_SUCCESS) { int copy_ret = -1; if (output.PoutFlags & BC_POUT_FLAGS_PIB_VALID) { - if (avctx->codec->id == AV_CODEC_ID_MPEG4 && - output.PicInfo.timeStamp == 0 && priv->bframe_bug) { - if (!priv->bframe_bug) { - av_log(avctx, AV_LOG_VERBOSE, - "CrystalHD: Not returning packed frame twice.\n"); - } - DtsReleaseOutputBuffs(dev, NULL, FALSE); - return RET_COPY_AGAIN; - } - print_frame_info(priv, &output); copy_ret = copy_frame(avctx, &output, frame, got_frame); @@ -763,85 +663,35 @@ static int crystalhd_decode_packet(AVCodecContext *avctx, const AVPacket *avpkt) av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: decode_packet\n"); if (avpkt && avpkt->size) { - int32_t tx_free = (int32_t)DtsTxFreeSize(dev); - - if (!priv->bframe_bug && (avpkt->size == 6 || avpkt->size == 7)) { - /* - * Drop frames trigger the bug - */ - av_log(avctx, AV_LOG_WARNING, - "CrystalHD: Enabling work-around for packed b-frame bug\n"); - priv->bframe_bug = 1; - } else if (priv->bframe_bug && avpkt->size == 8) { - /* - * Delay frames don't trigger the bug - */ - av_log(avctx, AV_LOG_WARNING, - "CrystalHD: Disabling work-around for packed b-frame bug\n"); - priv->bframe_bug = 0; - } - - if (priv->bsfc) { - AVPacket filter_packet = { 0 }; - - ret = av_packet_ref(&filter_packet, avpkt); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "CrystalHD: mpv4toannexb filter " - "failed to ref input packet\n"); - goto exit; - } - - ret = av_bsf_send_packet(priv->bsfc, &filter_packet); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "CrystalHD: mpv4toannexb filter " - "failed to send input packet\n"); - goto exit; - } - - ret = av_bsf_receive_packet(priv->bsfc, &filtered_packet); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "CrystalHD: mpv4toannexb filter " - "failed to receive output packet\n"); - goto exit; - } - - avpkt = &filtered_packet; - av_packet_unref(&filter_packet); + uint64_t pts; + + /* + * Despite being notionally opaque, either libcrystalhd or + * the hardware itself will mangle pts values that are too + * small or too large. The docs claim it should be in units + * of 100ns. Given that we're nominally dealing with a black + * box on both sides, any transform we do has no guarantee of + * avoiding mangling so we need to build a mapping to values + * we know will not be mangled. + */ + pts = opaque_list_push(priv, avpkt->pts); + if (!pts) { + ret = AVERROR(ENOMEM); + goto exit; } - - if (avpkt->size < tx_free) { - /* - * Despite being notionally opaque, either libcrystalhd or - * the hardware itself will mangle pts values that are too - * small or too large. The docs claim it should be in units - * of 100ns. Given that we're nominally dealing with a black - * box on both sides, any transform we do has no guarantee of - * avoiding mangling so we need to build a mapping to values - * we know will not be mangled. - */ - uint64_t pts = opaque_list_push(priv, avpkt->pts); - if (!pts) { - ret = AVERROR(ENOMEM); - goto exit; - } - av_log(priv->avctx, AV_LOG_VERBOSE, - "input \"pts\": %"PRIu64"\n", pts); - bc_ret = DtsProcInput(dev, avpkt->data, avpkt->size, pts, 0); - if (bc_ret == BC_STS_BUSY) { - av_log(avctx, AV_LOG_WARNING, - "CrystalHD: ProcInput returned busy\n"); - ret = AVERROR(EAGAIN); - goto exit; - } else if (bc_ret != BC_STS_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, - "CrystalHD: ProcInput failed: %u\n", ret); - ret = -1; - goto exit; - } - } else { - av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Input buffer full\n"); + av_log(priv->avctx, AV_LOG_VERBOSE, + "input \"pts\": %"PRIu64"\n", pts); + bc_ret = DtsProcInput(dev, avpkt->data, avpkt->size, pts, 0); + if (bc_ret == BC_STS_BUSY) { + av_log(avctx, AV_LOG_WARNING, + "CrystalHD: ProcInput returned busy\n"); ret = AVERROR(EAGAIN); goto exit; + } else if (bc_ret != BC_STS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, + "CrystalHD: ProcInput failed: %u\n", ret); + ret = -1; + goto exit; } } else { av_log(avctx, AV_LOG_INFO, "CrystalHD: No more input data\n"); @@ -862,9 +712,35 @@ static int crystalhd_receive_frame(AVCodecContext *avctx, AVFrame *frame) CHDContext *priv = avctx->priv_data; HANDLE dev = priv->dev; int got_frame = 0; + int ret = 0; + AVPacket pkt = {0}; av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: receive_frame\n"); + ret = ff_decode_get_packet(avctx, &pkt); + if (ret < 0 && ret != AVERROR_EOF) { + return ret; + } + + while (pkt.size > DtsTxFreeSize(dev)) { + /* + * Block until there is space in the buffer for the next packet. + * We assume that the hardware will make forward progress at this + * point, although in pathological cases that may not happen. + */ + av_log(avctx, AV_LOG_TRACE, "CrystalHD: Waiting for space in input buffer\n"); + } + + ret = crystalhd_decode_packet(avctx, &pkt); + av_packet_unref(&pkt); + // crystalhd_is_buffer_full() should avoid this. + if (ret == AVERROR(EAGAIN)) { + ret = AVERROR_EXTERNAL; + } + if (ret < 0 && ret != AVERROR_EOF) { + return ret; + } + do { bc_ret = DtsGetDriverStatus(dev, &decoder_status); if (bc_ret != BC_STS_SUCCESS) { @@ -873,7 +749,7 @@ static int crystalhd_receive_frame(AVCodecContext *avctx, AVFrame *frame) } if (decoder_status.ReadyListCount == 0) { - av_log(avctx, AV_LOG_INFO, "CrystalHD: Insufficient frames ready. Returning\n"); + av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Insufficient frames ready. Returning\n"); got_frame = 0; rec_ret = RET_OK; break; @@ -891,7 +767,7 @@ static int crystalhd_receive_frame(AVCodecContext *avctx, AVFrame *frame) } } -#define DEFINE_CRYSTALHD_DECODER(x, X) \ +#define DEFINE_CRYSTALHD_DECODER(x, X, bsf_name) \ static const AVClass x##_crystalhd_class = { \ .class_name = #x "_crystalhd", \ .item_name = av_default_item_name, \ @@ -907,33 +783,33 @@ static int crystalhd_receive_frame(AVCodecContext *avctx, AVFrame *frame) .priv_class = &x##_crystalhd_class, \ .init = init, \ .close = uninit, \ - .send_packet = crystalhd_decode_packet, \ .receive_frame = crystalhd_receive_frame, \ .flush = flush, \ + .bsfs = bsf_name, \ .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \ .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE}, \ }; #if CONFIG_H264_CRYSTALHD_DECODER -DEFINE_CRYSTALHD_DECODER(h264, H264) +DEFINE_CRYSTALHD_DECODER(h264, H264, "h264_mp4toannexb") #endif #if CONFIG_MPEG2_CRYSTALHD_DECODER -DEFINE_CRYSTALHD_DECODER(mpeg2, MPEG2VIDEO) +DEFINE_CRYSTALHD_DECODER(mpeg2, MPEG2VIDEO, NULL) #endif #if CONFIG_MPEG4_CRYSTALHD_DECODER -DEFINE_CRYSTALHD_DECODER(mpeg4, MPEG4) +DEFINE_CRYSTALHD_DECODER(mpeg4, MPEG4, "mpeg4_unpack_bframes") #endif #if CONFIG_MSMPEG4_CRYSTALHD_DECODER -DEFINE_CRYSTALHD_DECODER(msmpeg4, MSMPEG4V3) +DEFINE_CRYSTALHD_DECODER(msmpeg4, MSMPEG4V3, NULL) #endif #if CONFIG_VC1_CRYSTALHD_DECODER -DEFINE_CRYSTALHD_DECODER(vc1, VC1) +DEFINE_CRYSTALHD_DECODER(vc1, VC1, NULL) #endif #if CONFIG_WMV3_CRYSTALHD_DECODER -DEFINE_CRYSTALHD_DECODER(wmv3, WMV3) +DEFINE_CRYSTALHD_DECODER(wmv3, WMV3, NULL) #endif