X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fqsvdec_h264.c;h=78356e314024643d102f19ab1b3172fb8ab3818f;hb=0b159e3b65d53cbb7e66a1e10850927275fb2a1e;hp=1e9dff13c12c4fbc30b4cf9b595f5410a927c2dd;hpb=b97e3e11a9c23e45ac3b2c1a7771d55f8fc1caee;p=ffmpeg diff --git a/libavcodec/qsvdec_h264.c b/libavcodec/qsvdec_h264.c index 1e9dff13c12..78356e31402 100644 --- a/libavcodec/qsvdec_h264.c +++ b/libavcodec/qsvdec_h264.c @@ -39,48 +39,18 @@ typedef struct QSVH264Context { AVClass *class; QSVContext qsv; - // the internal parser and codec context for parsing the data - AVCodecParserContext *parser; - AVCodecContext *avctx_internal; - enum AVPixelFormat orig_pix_fmt; - // the filter for converting to Annex B AVBitStreamFilterContext *bsf; - AVFifoBuffer *packet_fifo; - - AVPacket input_ref; - AVPacket pkt_filtered; - uint8_t *filtered_data; } QSVH264Context; -static void qsv_clear_buffers(QSVH264Context *s) -{ - AVPacket pkt; - while (av_fifo_size(s->packet_fifo) >= sizeof(pkt)) { - av_fifo_generic_read(s->packet_fifo, &pkt, sizeof(pkt), NULL); - av_packet_unref(&pkt); - } - - if (s->filtered_data != s->input_ref.data) - av_freep(&s->filtered_data); - s->filtered_data = NULL; - av_packet_unref(&s->input_ref); -} - static av_cold int qsv_decode_close(AVCodecContext *avctx) { QSVH264Context *s = avctx->priv_data; ff_qsv_decode_close(&s->qsv); - qsv_clear_buffers(s); - - av_fifo_free(s->packet_fifo); - av_bitstream_filter_close(s->bsf); - av_parser_close(s->parser); - avcodec_free_context(&s->avctx_internal); return 0; } @@ -90,179 +60,60 @@ static av_cold int qsv_decode_init(AVCodecContext *avctx) QSVH264Context *s = avctx->priv_data; int ret; - s->orig_pix_fmt = AV_PIX_FMT_NONE; - - s->packet_fifo = av_fifo_alloc(sizeof(AVPacket)); - if (!s->packet_fifo) { - ret = AVERROR(ENOMEM); - goto fail; - } - s->bsf = av_bitstream_filter_init("h264_mp4toannexb"); if (!s->bsf) { ret = AVERROR(ENOMEM); goto fail; } - s->avctx_internal = avcodec_alloc_context3(NULL); - if (!s->avctx_internal) { - ret = AVERROR(ENOMEM); - goto fail; - } - - if (avctx->extradata) { - s->avctx_internal->extradata = av_mallocz(avctx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - if (!s->avctx_internal->extradata) { - ret = AVERROR(ENOMEM); - goto fail; - } - memcpy(s->avctx_internal->extradata, avctx->extradata, - avctx->extradata_size); - s->avctx_internal->extradata_size = avctx->extradata_size; - } - - s->parser = av_parser_init(AV_CODEC_ID_H264); - if (!s->parser) { - ret = AVERROR(ENOMEM); - goto fail; - } - s->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES; - return 0; fail: qsv_decode_close(avctx); return ret; } -static int qsv_process_data(AVCodecContext *avctx, AVFrame *frame, - int *got_frame, AVPacket *pkt) -{ - QSVH264Context *s = avctx->priv_data; - uint8_t *dummy_data; - int dummy_size; - int ret; - - /* we assume the packets are already split properly and want - * just the codec parameters here */ - av_parser_parse2(s->parser, s->avctx_internal, - &dummy_data, &dummy_size, - pkt->data, pkt->size, pkt->pts, pkt->dts, - pkt->pos); - - /* TODO: flush delayed frames on reinit */ - if (s->parser->format != s->orig_pix_fmt || - s->parser->coded_width != avctx->coded_width || - s->parser->coded_height != avctx->coded_height) { - - enum AVPixelFormat pix_fmts[3] = { AV_PIX_FMT_QSV, - AV_PIX_FMT_NONE, - AV_PIX_FMT_NONE }; - enum AVPixelFormat qsv_format; - - qsv_format = ff_qsv_map_pixfmt(s->parser->format); - if (qsv_format < 0) { - av_log(avctx, AV_LOG_ERROR, - "Only 8-bit YUV420 streams are supported.\n"); - ret = AVERROR(ENOSYS); - goto reinit_fail; - } - - s->orig_pix_fmt = s->parser->format; - avctx->pix_fmt = pix_fmts[1] = qsv_format; - avctx->width = s->parser->width; - avctx->height = s->parser->height; - avctx->coded_width = s->parser->coded_width; - avctx->coded_height = s->parser->coded_height; - avctx->level = s->avctx_internal->level; - avctx->profile = s->avctx_internal->profile; - - ret = ff_get_format(avctx, pix_fmts); - if (ret < 0) - goto reinit_fail; - - avctx->pix_fmt = ret; - - ret = ff_qsv_decode_init(avctx, &s->qsv); - if (ret < 0) - goto reinit_fail; - } - - return ff_qsv_decode(avctx, &s->qsv, frame, got_frame, &s->pkt_filtered); - -reinit_fail: - s->orig_pix_fmt = s->parser->format = avctx->pix_fmt = AV_PIX_FMT_NONE; - return ret; -} - static int qsv_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { QSVH264Context *s = avctx->priv_data; AVFrame *frame = data; int ret; + uint8_t *p_filtered = NULL; + int n_filtered = NULL; + AVPacket pkt_filtered = { 0 }; - /* buffer the input packet */ if (avpkt->size) { - AVPacket input_ref = { 0 }; - - if (av_fifo_space(s->packet_fifo) < sizeof(input_ref)) { - ret = av_fifo_realloc2(s->packet_fifo, - av_fifo_size(s->packet_fifo) + sizeof(input_ref)); - if (ret < 0) - return ret; - } - - ret = av_packet_ref(&input_ref, avpkt); - if (ret < 0) - return ret; - av_fifo_generic_write(s->packet_fifo, &input_ref, sizeof(input_ref), NULL); - } - - /* process buffered data */ - while (!*got_frame) { - /* prepare the input data -- convert to Annex B if needed */ - if (s->pkt_filtered.size <= 0) { - int size; + if (avpkt->size > 3 && !avpkt->data[0] && + !avpkt->data[1] && !avpkt->data[2] && 1==avpkt->data[3]) { + /* we already have annex-b prefix */ + return ff_qsv_decode(avctx, &s->qsv, frame, got_frame, avpkt); - /* no more data */ - if (av_fifo_size(s->packet_fifo) < sizeof(AVPacket)) - return avpkt->size ? avpkt->size : ff_qsv_decode(avctx, &s->qsv, frame, got_frame, avpkt); - - if (s->filtered_data != s->input_ref.data) - av_freep(&s->filtered_data); - s->filtered_data = NULL; - av_packet_unref(&s->input_ref); - - av_fifo_generic_read(s->packet_fifo, &s->input_ref, sizeof(s->input_ref), NULL); + } else { + /* no annex-b prefix. try to restore: */ ret = av_bitstream_filter_filter(s->bsf, avctx, NULL, - &s->filtered_data, &size, - s->input_ref.data, s->input_ref.size, 0); - if (ret < 0) { - s->filtered_data = s->input_ref.data; - size = s->input_ref.size; + &p_filtered, &n_filtered, + avpkt->data, avpkt->size, 0); + if (ret>=0) { + pkt_filtered.pts = avpkt->pts; + pkt_filtered.data = p_filtered; + pkt_filtered.size = n_filtered; + + ret = ff_qsv_decode(avctx, &s->qsv, frame, got_frame, &pkt_filtered); + + if (p_filtered != avpkt->data) + av_free(p_filtered); + return ret > 0 ? avpkt->size : ret; } - s->pkt_filtered = s->input_ref; - s->pkt_filtered.data = s->filtered_data; - s->pkt_filtered.size = size; } - - ret = qsv_process_data(avctx, frame, got_frame, &s->pkt_filtered); - if (ret < 0) - return ret; - - s->pkt_filtered.size -= ret; - s->pkt_filtered.data += ret; } - return avpkt->size; + return ff_qsv_decode(avctx, &s->qsv, frame, got_frame, avpkt); } static void qsv_decode_flush(AVCodecContext *avctx) { - QSVH264Context *s = avctx->priv_data; - - qsv_clear_buffers(s); - s->orig_pix_fmt = AV_PIX_FMT_NONE; +// QSVH264Context *s = avctx->priv_data; + /* TODO: flush qsv engine if necessary */ } AVHWAccel ff_h264_qsv_hwaccel = {