[FFmpeg-devel] [PATCH] lavc/dxva2: add ffmpeg calling dxva2 APIs
Wei Gao
highgod0401 at gmail.com
Mon Jun 24 14:20:08 CEST 2013
Hi,
Thanks for your reply, some questions are as follows
Thanks.
Best regards
2013/6/21 Laurent Aimar <fenrir at elivagar.org>
> Hi,
>
>
>
> > +
> > +static int get_buffer2(struct AVCodecContext *avctx, AVFrame *pic, int
> flags)
> > +{
> > + int ret;
> > + DXVA2_DecoderContext *ctx = (DXVA2_DecoderContext
> *)avctx->priv_data;
> > + dxva2_context *dxva2_ctx = &ctx->dxva2_ctx;
> > + avctx->pix_fmt = ctx->pix_fmt;
> Why do you copy the pix_fmt here ? And is that valid ?
>
I will remove it
>
> > + ff_init_buffer_info(avctx, pic);
> > +
> > + if ((ret = ctx->get_buffer2(avctx, pic, flags)) < 0) {
> > + return ret;
> > + }
> > + if (dxva2_ctx) {
> I don't see how dxva2_ctx can be NULL.
>
Do you mean the dxva2_ctx always be valid?
>
>
> > +static int dxva2dec_decode(AVCodecContext *avctx, void *data, int
> *got_frame,
> > + AVPacket *avpkt)
> > +{
> > + DXVA2_DecoderContext *ctx = (DXVA2_DecoderContext
> *)avctx->priv_data;
> > + AVFrame *pic = data;
> > + int ret;
> > + AVCodec *codec = ctx->codec;
> > + ret = codec->decode(avctx, data, got_frame, avpkt);
> > + if (*got_frame) {
> I don't remember if it is valid to check on got_frame without first
> checking ret.
>
I will add check the ret
>
> > + pic->format = ctx->pix_fmt;
> > + ff_extract_dxva2(&ctx->dxva2_ctx, pic);
> > + }
> > + avctx->pix_fmt = ctx->pix_fmt;
> Why do you copy the pix_fmt here too ? And is that valid ?
>
will remove it
>
> > + return ret;
> > +}
> > +
> > +static av_cold int dxva2dec_close(AVCodecContext *avctx)
> > +{
> > + DXVA2_DecoderContext *ctx = avctx->priv_data;
> > + AVCodec *codec = ctx->codec;
> > + /* release buffers and decoder */
> > + ff_release_dxva2(&ctx->dxva2_ctx);
> You probably need to flush the decoder first to ensure that all remaing
> pictures are
> released before destroying the dxva2 context.
>
add codec->flush(avctx);, is it right?
>
> > + /* close decoder */
> > + codec->close(avctx);
> > + return 0;
> > +}
> > +static int get_mpeg2_video_format(AVCodecContext *avctx)
> > +{
> > + Mpeg1Context *s = avctx->priv_data;
> > + MpegEncContext *s2 = &s->mpeg_enc_ctx;
> Is that a valid access when using the decoder part only ?
Sorry, I don't konw is there anyway to access the data, because I think the
format should be check.Can anyone give any advice?
>
> > + const uint8_t *buf_ptr = avctx->extradata;
> > + const uint8_t *buf_end = avctx->extradata + avctx->extradata_size;
> > + int input_size, format = -1;
> > + if (avctx->extradata) {
> > + for (;;) {
> > + uint32_t start_code = -1;
> Using UIN32_MAX would be cleaner IMHO.
>
OK, will fix
>
> > + buf_ptr = avpriv_find_start_code(buf_ptr, buf_end,
> &start_code);
> > + input_size = buf_end - buf_ptr;
> > + if (EXT_START_CODE == start_code) {
> > + init_get_bits(&s2->gb, buf_ptr, input_size * 8);
> Is it valid to use a get bit context private to the Mpeg1Context context ?
>
I only konw this way to get the format code.
>
> > + switch (get_bits(&s2->gb, 4)) {
> > + case 0x1:
> > + skip_bits(&s2->gb, 9);
> > + format = get_bits(&s2->gb, 2);
> > + return format;
> > + }
> > + }
> > + if (input_size <= 0) {
> > + av_log(avctx, AV_LOG_ERROR,"get_mpeg2_video_format
> error\n");
> > + return format;
> > + }
> It would be cleaner to move it before trying to use the buffer in case of
> a start
> code match.
>
sorry, I don't get what you mean
>
> > + }
> > + }
> > + av_log(avctx, AV_LOG_ERROR,"get_mpeg2_video_format error\n");
> > + return format;
> > +}
> > +
> > +static int check_format(AVCodecContext *avctx)
> > +{
> > + uint8_t *pout;
> > + int psize, index, ret = -1;
> > + H264Context *h;
> > + AVCodecParserContext *parser = NULL;
> I think it's a useless initialization.
>
> will remove it
> > + /* check if support */
> > + switch (avctx->codec_id) {
> > + case AV_CODEC_ID_H264:
> > + /* init parser & parse file */
> > + parser = av_parser_init(avctx->codec->id);
> > + if (!parser) {
> > + av_log(avctx, AV_LOG_ERROR, "Failed to open parser.\n");
> > + break;
> > + }
> > + parser->flags = PARSER_FLAG_COMPLETE_FRAMES;
> > + index = av_parser_parse2(parser, avctx, &pout, &psize, NULL, 0,
> 0, 0, 0);
> > + if (index < 0) {
> > + av_log(avctx, AV_LOG_ERROR, "Failed to parse this file.\n");
> Weird error message.
>
> > + av_parser_close(parser);
> > + }
> > + h = parser->priv_data;
> Is that valid when you just closed the parser in case of error ?
>
> > + if (8 == h->sps.bit_depth_luma) {
> > + if (!CHROMA444(h) && !CHROMA422(h)) {
> > + // only this will decoder switch to hwaccel
> > + //check the profile
> > + if ((FF_PROFILE_H264_BASELINE == h->sps.profile_idc) ||
> > + (FF_PROFILE_H264_MAIN == h->sps.profile_idc) ||
> > + (FF_PROFILE_H264_HIGH == h->sps.profile_idc)) {
> If you really want to check the compatibility, you need more checks (you
> may
> want to have a look at MPC code).
>
I reference the vda_h264_dec.c code, and it seems just check these things
switch (h->sps.bit_depth_luma) {
case 8:
if (!CHROMA444(h) && !CHROMA422(h)) {
// only this will H.264 decoder switch to hwaccel
ret = 0;
break;
}
default:
av_log(avctx, AV_LOG_ERROR, "Unsupported file.\n");
}
> + ret = 0;
> > + } else {
> > + av_log(avctx, AV_LOG_ERROR, "Unsupported
> profile.\n");
> > + }
> > + av_parser_close(parser);
> > + break;
> > + }
> > + } else {
> > + av_log(avctx, AV_LOG_ERROR, "Unsupported file.\n");
> Weird error message.
> > + av_parser_close(parser);
> > + break;
> > + }
> You could probably factorized all the av_parser_close() calls.
>
OK
> > + break;
> > + case AV_CODEC_ID_MPEG2VIDEO:
> > + if (CHROMA_420 == get_mpeg2_video_format(avctx)) {
> > + ret = 0;
> > + break;
> > + } else {
> > + av_log(avctx, AV_LOG_ERROR, "Unsupported file.\n");
> Weird error message.
> > + break;
> > + }
> > + default:
> > + ret = 0;
> > + break;
> > + }
> I think that returning directly when needed instead of using the ret
> variable
> would create a simpler and easier to read code.
>
> > + return ret;
> > +}
> > +
> > +static av_cold int dxva2dec_init(AVCodecContext *avctx)
> > +{
> > + DXVA2_DecoderContext *ctx = (DXVA2_DecoderContext
> *)avctx->priv_data;
> > + dxva2_context *dxva2_ctx = (dxva2_context *)(&ctx->dxva2_ctx);
> > + AVCodec *hwcodec, *codec;
> > + int ret;
> > + ctx->initialized = 0;
> > + get_hw_soft_codec(avctx,ctx);
> > + hwcodec = ctx->hwcodec;
> > + codec = ctx->codec;
> > + /* init pix_fmts of codec */
> > + if (!hwcodec->pix_fmts) {
> > + hwcodec->pix_fmts = dxva2_pixfmts;
> > + }
> I don't know how that works, could someone double check ?
>
Sorry, do you mean does the code can run? I tested on my computer, it can
run.
>
> > + /* check if DXVA2 supports this file */
> > + if (check_format(avctx) < 0)
> > + return AVERROR(EINVAL);
> I am not sure that's its acceptable. You may not have any extradata when
> the codec
> is instantiated. In addition, the codec profile, or chroma type may change
> while
> decoding.
>
> do you mean I should check the format during the decode?
> > +
> > + /* init vda */
> > + memset(dxva2_ctx, 0, sizeof(dxva2_context));
> > + ret = ff_create_dxva2(avctx->codec_id, dxva2_ctx);
> > + if (ret < 0) {
> > + av_log(avctx, AV_LOG_ERROR, "create dxva2 error\n");
> > + return AVERROR(EINVAL);
> > + }
> > + ctx->pix_fmt = avctx->get_format(avctx, avctx->codec->pix_fmts);
> > + ret = ff_setup_dxva2(dxva2_ctx, &avctx->hwaccel_context,
> &avctx->pix_fmt, avctx->width, avctx->height);
> > + if (ret < 0) {
> > + av_log(avctx,AV_LOG_ERROR,"error DXVA setup %d\n", ret);
> > + ret = AVERROR(EINVAL);
> > + goto failed;
> > + }
> I am not sure that's its also acceptable. The video dimension may change
> while
> decoding. You may have a look at VLC to see how we handle that.
>
OK, the dxva file?
>
> > + avctx->slice_flags |= SLICE_FLAG_ALLOW_FIELD;
> Do you need that ?
>
> > + /* changes callback functions */
> > + ctx->get_buffer2 = avctx->get_buffer2;
> > + avctx->get_format = get_format;
> Are you sure it is valid to basically ignore the get_format of the user ?
>
> > + avctx->get_buffer2 = get_buffer2;
> You overload the get_buffer2 but I do not see you overloading the
> associated
> release function. So it probably means you are not releasing correctly the
> dxva2
> surface handle that get associated to the picture by get_buffer2...
>
I reference the code of ffmpeg, and vda_h264_dec.c , it seems that the
release function is not valid in this version
the vda code is as follows:
/* changes callback functions */
avctx->get_format = get_format;
avctx->get_buffer2 = get_buffer2;
#if FF_API_GET_BUFFER
// force the old get_buffer to be empty
avctx->get_buffer = NULL;
#endif
> > + /* init decoder */
> > +
> > + ret = codec->init(avctx);
> > + if (ret < 0) {
> > + av_log(avctx, AV_LOG_ERROR, "Failed to open decoder.\n");
> > + goto failed;
> > + }
> > + ctx->initialized = 1;
> > + return 0;
> > +failed:
> > + dxva2dec_close(avctx);
> > + return ret;
> > +}
> I have some doubt about the way the avctx context is shared by both
> decoder. Could
> someone check that ?
>
I reference the vda code. I test on my computer, it works.
>
> Also, it would probably be better to disable any threading as it becomes
> useless
> and may break the decoding (I am not sure all the bugs have been fixed in
> that
> regards).
>
> > +
> > +static void dxva2dec_flush(AVCodecContext *avctx)
> > +{
> > + DXVA2_DecoderContext *ctx = (DXVA2_DecoderContext
> *)avctx->priv_data;
> > + AVCodec *codec = ctx->codec;
> > + return codec->flush(avctx);
> > +}
> > +#if CONFIG_H264_DXVA2_DECODER
> > +AVCodec ff_h264_dxva2_decoder = {
> > + .name = "h264_dxva2",
> > + .type = AVMEDIA_TYPE_VIDEO,
> > + .id = AV_CODEC_ID_H264,
> > + .priv_data_size = sizeof(DXVA2_DecoderContext),
> > + .init = dxva2dec_init,
> > + .close = dxva2dec_close,
> > + .decode = dxva2dec_decode,
> > + .capabilities = CODEC_CAP_DELAY,
> > + .flush = dxva2dec_flush,
> > + .long_name = NULL_IF_CONFIG_SMALL("H.264 (DXVA2
> acceleration)"),
> > +};
> > +#endif
> > +
> > +#if CONFIG_MPEG2VIDEO_DXVA2_DECODER
> > +AVCodec ff_mpeg2video_dxva2_decoder = {
> > + .name = "mpeg2video_dxva2",
> > + .type = AVMEDIA_TYPE_VIDEO,
> > + .id = AV_CODEC_ID_MPEG2VIDEO,
> > + .priv_data_size = sizeof(DXVA2_DecoderContext),
> > + .init = dxva2dec_init,
> > + .close = dxva2dec_close,
> > + .decode = dxva2dec_decode,
> > + .capabilities = CODEC_CAP_DELAY,
> > + .flush = dxva2dec_flush,
> > + .long_name = NULL_IF_CONFIG_SMALL("MPEG2 Video (DXVA2
> acceleration)"),
> > +};
> > +#endif
> > +
> > +#if CONFIG_VC1_DXVA2_DECODER
> > +AVCodec ff_vc1_dxva2_decoder = {
> > + .name = "vc1_dxva2",
> > + .type = AVMEDIA_TYPE_VIDEO,
> > + .id = AV_CODEC_ID_VC1,
> > + .priv_data_size = sizeof(DXVA2_DecoderContext),
> > + .init = dxva2dec_init,
> > + .close = dxva2dec_close,
> > + .decode = dxva2dec_decode,
> > + .capabilities = CODEC_CAP_DELAY,
> > + .flush = dxva2dec_flush,
> > + .long_name = NULL_IF_CONFIG_SMALL("VC1 (DXVA2 acceleration)"),
> > +};
> > +#endif
> > +
> > +#if CONFIG_WMV3_DXVA2_DECODER
> > +AVCodec ff_wmv3_dxva2_decoder = {
> > + .name = "wmv3_dxva2",
> > + .type = AVMEDIA_TYPE_VIDEO,
> > + .id = AV_CODEC_ID_WMV3,
> > + .priv_data_size = sizeof(DXVA2_DecoderContext),
> > + .init = dxva2dec_init,
> > + .close = dxva2dec_close,
> > + .decode = dxva2dec_decode,
> > + .capabilities = CODEC_CAP_DELAY,
> > + .flush = dxva2dec_flush,
> > + .long_name = NULL_IF_CONFIG_SMALL("WMV3 (DXVA2 acceleration)"),
> > +};
> > +#endif
>
> I will review the rest of the patch once the already commented code has
> been
> processed.
>
> Regards,
>
> --
> fenrir
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
>
More information about the ffmpeg-devel
mailing list