On 24/01/16 14:52, wm4 wrote: > On Sun, 24 Jan 2016 14:20:54 +0000 > Mark Thompson <s...@jkqxz.net> wrote: > > ... > >>>> + >>>> + new_frame = av_frame_alloc(); >>>> + if(!new_frame) >>>> + return AVERROR(ENOMEM); >>>> + >>>> + av_vaapi_surface_pool_get(&ctx->pool, new_frame); >>>> + >>>> + av_log(ctx, AV_LOG_DEBUG, "Decoder given reference to surface %#x.\n", >>>> + (VASurfaceID)new_frame->data[3]); >>>> + >>>> + av_frame_copy_props(new_frame, frame); >>>> + av_frame_unref(frame); >>>> + av_frame_move_ref(frame, new_frame); >>> >>> What are these acrobatics for? Why not use frame directly? >> >> The AVFrame supplied by the decoder already has a lot of the metadata filled >> in, but the surface pool needs to make a new reference to its own AVFrame. >> >> Without this, you get display order == decode order (that was fun to track >> down). > > I still don't understand - AVFrames aren't referenced, AVBufferRefs > are.
av_vaapi_surface_pool_get() wants a whole new AVFrame so that it can call av_frame_ref() to make the buffers new references to the existing things held in its frame pool. I could change this so that it just fills in buf[0], buf[1] and data[3] (and more?) and then it could be called directly on the given AVFrame here, but that seems like it would introduce inconvenient subtlety for other users. >> ... >>>> + // If there isn't an exact match, we will choose the last >>>> (highest) >>>> + // profile in the mapping table. This is unfortunate because it >>>> + // could well be wrong, but it improves compatibility because >>>> streams >>>> + // and decoders do not necessarily conform to the requirements. >>>> + // (Without this, a lot of streams in FATE are discarded when then >>>> + // could have worked - H.264 extended profile which actually >>>> decodes >>>> + // with main, for example.) >>> >>> I still think this should not be done by default, and instead a user >>> option should enable it. >> >> I guess that works if the error message suggests the option they could try. >> "-lax-codec-profile-constraints"? Other hwaccels might want it too. > > Yes, something like this. At least vdpau already checks it pretty > strictly (even verifies the level). Ok, I'll look into it. >> ... >>>> + >>>> + // Decide on the internal chroma format. >>>> + { >>>> + VAConfigAttrib attr; >>>> + >>>> + // Currently the software only supports YUV420, so just make sure >>>> + // that the hardware we have does too. >>>> + >>>> + memset(&attr, 0, sizeof(attr)); >>>> + attr.type = VAConfigAttribRTFormat; >>>> + vas = vaGetConfigAttributes(ctx->hardware_context->display, >>>> config->profile, >>>> + VAEntrypointVLD, &attr, 1); >>>> + if(vas != VA_STATUS_SUCCESS) { >>>> + av_log(ctx, AV_LOG_ERROR, "Failed to fetch config attributes: >>>> " >>>> + "%d (%s).\n", vas, vaErrorStr(vas)); >>>> + return AVERROR(EINVAL); >>>> + } >>>> + if(!(attr.value & VA_RT_FORMAT_YUV420)) { >>>> + av_log(ctx, AV_LOG_ERROR, "Hardware does not support required >>>> " >>>> + "chroma format (%#x).\n", attr.value); >>>> + return AVERROR(EINVAL); >>>> + } >>>> + >>>> + output->rt_format = VA_RT_FORMAT_YUV420; >>> >>> I'm confused, shouldn't this set it to something retrieved by the >>> function above? >> >> Read again - it's just a check, the code errors out on all other >> possibilities. >> > > Oh, ok. > >> This section is only present because more could be added. Currently the >> only other possibility in the Intel driver is greyscale for H.264 decoding >> only, so it didn't seem worth it now. >> > > What about conversion to RGB? I think 10 bit will also have a different > RT format, not sure. This is only deciding on the format of the surface which the decoder actually operates on, which isn't going to be RGB. YUV 10-bit does have a different format - implementing that will need support here to select VA_RT_FORMAT_YUV420_10BIT. >>>> + } >>>> + >>>> + // Decide on the image format. >>>> + if(avctx->pix_fmt == AV_PIX_FMT_VAAPI) { >>>> + // We are going to be passing through a VAAPI surface directly: >>>> + // they will stay as whatever opaque internal format for that >>>> time, >>>> + // and we never need to make VAImages from them. >>>> + >>>> + av_log(ctx, AV_LOG_DEBUG, "Using VAAPI opaque output format.\n"); >>>> + >>>> + output->av_format = AV_PIX_FMT_VAAPI; >>>> + memset(&output->image_format, 0, sizeof(output->image_format)); >>>> + >>>> + } else { >>>> + int image_format_count; >>>> + VAImageFormat *image_format_list; >>>> + int pix_fmt; >>>> + >>>> + // We might want to force a change to the output format here >>>> + // if we are intending to use VADeriveImage? >>>> + >>>> + image_format_count = >>>> vaMaxNumImageFormats(ctx->hardware_context->display); >>>> + image_format_list = av_calloc(image_format_count, >>>> + sizeof(VAImageFormat)); >>>> + if(!image_format_list) >>>> + return AVERROR(ENOMEM); >>>> + >>>> + vas = vaQueryImageFormats(ctx->hardware_context->display, >>>> image_format_list, >>>> + &image_format_count); >>>> + if(vas != VA_STATUS_SUCCESS) { >>>> + av_log(ctx, AV_LOG_ERROR, "Failed to query image formats: " >>>> + "%d (%s).\n", vas, vaErrorStr(vas)); >>>> + return AVERROR(EINVAL); >>>> + } >>>> + >>>> + for(i = 0; i < image_format_count; i++) { >>>> + pix_fmt = vaapi_get_pix_fmt(image_format_list[i].fourcc); >>>> + if(pix_fmt == AV_PIX_FMT_NONE) >>>> + continue; >>>> + if(pix_fmt == avctx->pix_fmt) >>>> + break; >>>> + } >>>> + if(i < image_format_count) { >>>> + av_log(ctx, AV_LOG_DEBUG, "Using desired output format %s " >>>> + "(%#x).\n", av_get_pix_fmt_name(pix_fmt), >>>> + image_format_list[i].fourcc); >>>> + } else { >>>> + for(i = 0; i < image_format_count; i++) { >>>> + pix_fmt = vaapi_get_pix_fmt(image_format_list[i].fourcc); >>>> + if(pix_fmt != AV_PIX_FMT_NONE) >>>> + break; >>>> + } >>>> + if(i >= image_format_count) { >>>> + av_log(ctx, AV_LOG_ERROR, "No supported output format >>>> found.\n"); >>>> + av_free(image_format_list); >>>> + return AVERROR(EINVAL); >>>> + } >>>> + av_log(ctx, AV_LOG_DEBUG, "Using alternate output format %s " >>>> + "(%#x).\n", av_get_pix_fmt_name(pix_fmt), >>>> + image_format_list[i].fourcc); >>>> + } >>>> + >>>> + output->av_format = pix_fmt; >>>> + memcpy(&output->image_format, &image_format_list[i], >>>> + sizeof(VAImageFormat)); >>>> + >>>> + av_free(image_format_list); >>>> + } >>> >>> Seems to pick a format randomly (from the unordered image_format_list). >>> Maybe it'd just be better to force NV12, and if that doesn't work, >>> retry with yuv420p, or so. >> >> It picks the format you asked for (avctx->pix_fmt), or if not present takes >> the first usable one on the list. In practice you ask for YUV420P and >> probably get it, with NV12 otherwise. >> > > The first from the list returned by libva is still arbitrary. > > What's the format "you asked for"? Does this refer to the -pix_fmt > command line option, or whatever it was? > I was meaning the one supplied as AVCodecContext.pix_fmt. Looking again, I'm not sure this is actually meaningful. It's also the cause of the problem with FATE h264-reinit-large_420_8-to-small_420_8, so maybe the fixed-list suggestion is actually the way to go here. I'll think further on it. > ... Thanks, - Mark _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel