I am trying to figure out hardware decoding in ffmpeg in c ++. I get about the same errors on any api. Here is the initialization code:
AVHWDeviceType devType = av_hwdevice_find_type_by_name(HW_DECODER_NAME);
for (int i = 0;; i++)
{
const AVCodecHWConfig *config = avcodec_get_hw_config(av_codec, i);
if (!config)
{
fprintf(stderr, "Decoder %s does not support device type %s.\n",
av_codec->name, av_hwdevice_get_type_name(devType));
return false;
}
if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX && config->device_type == devType)
{
hw_pix_fmt = config->pix_fmt;
break;
}
}
hw_device_ctx = av_hwdevice_ctx_alloc(devType);
*av_codec_ctx = avcodec_alloc_context3(av_codec);
if (!av_codec_ctx)
{
printf("Couldn't create AVCodecContext\n");
return false;
}
if (avcodec_parameters_to_context(*av_codec_ctx, av_codec_params) < 0)
{
printf("Couldn't initialize AVCodecContext\n");
return false;
}
(*av_codec_ctx)->get_format = get_hw_format;
//Initialize hardware context
int err = 0;
if ((err = av_hwdevice_ctx_create(&hw_device_ctx, devType, NULL, NULL, 0)) < 0)
{
fprintf(stderr, "Failed to create specified HW device.\n");
return false;
}
(*av_codec_ctx)->hw_device_ctx = av_buffer_ref(hw_device_ctx);
if (avcodec_open2(*av_codec_ctx, av_codec, NULL) < 0)
{
printf("Couldn't open codec\n");
return false;
}
b_is_initialized = true;
Here is the decoder code:
int response;
response = avcodec_send_packet(av_codec_ctx, av_packet);
if (response < 0)
{
printf("Couldn't send video frame to decoder.\n");
print_error(response);
return false;
}
realloc_frame(&av_frame);
response = avcodec_receive_frame(av_codec_ctx, av_frame);
if (response == AVERROR(EAGAIN) || response == AVERROR_EOF)
{
av_frame_free(&av_frame);
return false;
}
else if (response < 0)
{
print_error(response);
return false;
}
if(hwdecoder.is_initialized())
{
if(!hwdecoder.decode(av_packet, &av_frame))
{
printf("Failed while decoding frame on gpu.\n");
}
}
pts = av_frame->pts;
// Set up sws scaler
if (!sws_scaler_ctx)
{
auto source_pix_fmt = correct_for_deprecated_pixel_format((AVPixelFormat)av_frame->format);
//Send here frame params
sws_scaler_ctx = sws_getContext(width, height, source_pix_fmt,
width, height, AV_PIX_FMT_RGB0,
SWS_BICUBIC, NULL, NULL, NULL);
Decoding on the processor works without problems, but when I decode on the gpu, it turns out to decode some part of the video and then during avcodec_send_packet
I get the Invalid data found when processing the input error. Help please, I have been suffering for the second week.
EDIT
OP forgot about hwdecoder.decode
method.
int ret = 0;
realloc_frame(&sw_frame);
if ((*av_frame)->format == hw_pix_fmt)
{
if ((ret = av_hwframe_transfer_data(sw_frame, *av_frame, 0)) < 0)
{
fprintf(stderr, "Error transferring the data to system memory\n");
av_frame_free(&sw_frame);
return false;
}
}
Error log:
Couldn't send video frame to decoder.
Invalid data found when processing input
[AVHWFramesContext @ 000001E44F6EC8C0] Static surface pool size exceeded.
[h264 @ 000001E445D60940] get_buffer() failed
[h264 @ 000001E445D60940] thread_get_buffer() failed
[h264 @ 000001E445D60940] decode_slice_header error
[h264 @ 000001E445D60940] no frame!
My code based on this example: https://ffmpeg.org/doxygen/4.0/hw_decode_8c-example.html
On windows i used dxva2 device, configure project with cmake 3.9, and build with MSVC amd64. On linux i used vdpau device, compiled from source ffmpeg libs, project was configured with cmake 3.9 and build with gcc 10
UPDATE
This code working well with cuda, but with another api's i still have problems.