当使用dxva2通过ffmpeg解码视频时,出现“执行失败:0x80070057”的错误。

11

我已成功地使用ffmpeg实现了一个视频播放器。现在,我正在尝试使用硬件解码,但我遇到了一些问题。 我找到了一篇文章作为起点,链接在这里:https://ffmpeg.org/pipermail/libav-user/2014-August/007323.html

我更新了设置解码所需内容的代码。更新后的代码可在此处获得:https://drive.google.com/file/d/0B5ufHdoDzA4ieVk5UVpxcDNzRHc/view?usp=sharing

以下是我用来初始化解码器的方式:

// Prepare the decoding context
AVCodec *codec = nullptr;
_codecContext = _avFormatContext->streams[_streamIndex]->codec;
if ((codec = avcodec_find_decoder(_codecContext->codec_id)) == 0)
{
    std::cout << "Unsupported video codec!" << std::endl;
    return false;
}

_codecContext->thread_count = 1;  // Multithreading is apparently not compatible with hardware decoding
InputStream *ist = new InputStream();
ist->hwaccel_id = HWACCEL_AUTO;
ist->hwaccel_device = "dxva2";
ist->dec = codec;
ist->dec_ctx = _codecContext;
_codecContext->coded_width = _width;
_codecContext->coded_height = _height;

_codecContext->opaque = ist;
dxva2_init(_codecContext);

_codecContext->get_buffer2 = ist->hwaccel_get_buffer;
_codecContext->get_format = GetHwFormat;
_codecContext->thread_safe_callbacks = 1;

if (avcodec_open2(_codecContext, codec, nullptr) < 0)
{
    std::cout << "Video codec open error" << std::endl;
    return false;
}

这里是上面提到的GetHwFormat的定义:

AVPixelFormat GetHwFormat(AVCodecContext *s, const AVPixelFormat *pix_fmts)
{
    InputStream* ist = (InputStream*)s->opaque;
    ist->active_hwaccel_id = HWACCEL_DXVA2;
    ist->hwaccel_pix_fmt = AV_PIX_FMT_DXVA2_VLD;
    return ist->hwaccel_pix_fmt;
}

当我打开一个h264编码的mp4视频,它的分辨率是高清或更低时,一切似乎都正常。但是,当我尝试更高分辨率的视频,比如3840x2160时,我会不断遇到以下错误:

Failed to execute: 0x80070057
Hardware accelerator failed to decode picture

几秒钟后,我还会开始收到以下错误:

co located POCs unavailable

视频无法正常显示:视频上出现了很多伪像,而且视频卡顿。我检查了ffmpeg源代码中的第一个错误,发现是因为无效参数引起的IDirectXVideoDecoder_Execute失败。由于这是在ffmpeg内发生的,一定有些我没有注意到的东西,但我无法弄清楚是什么。我找到的唯一与此错误相关的帖子是因为多线程,但在打开编解码器之前,我已将线程数设置为1。

我的主计算机遇到了这个问题,它的规格如下:

  • i7-4790 CPU @ 3.6GHz
  • RAM 16 GB
  • Intel HD Graphics 4600
  • Windows 8.1

我的第二台计算机规格如下,没有出现同样的问题:

  • i7 4510U @ 2GHz
  • RAM 8 GB
  • NVIDIA GeForce GTX 750Ti
  • Windows 10

如果我在主计算机上使用DXVAChecker,它会说我的显卡支持DXVA2进行H264_VLD_*的硬件加速,并且我可以看到视频播放时调用了Microsoft API(DXVA2_DecodeDeviceCreated、DXVA2_DecodeDeviceBeginFrame、DXVA2_DecodeDeviceGetBuffer、DXVA2_DecodeDeviceExecute、DXVA2_DecodeDeviceEndFrame)。

我在两台计算机上都没有看到GPU使用率的增加(无论是有硬件解码的版本还是没有硬件解码的版本),但是CPU使用率有所下降(虽然下降得不够明显)。这也非常奇怪。

请注意,我已尝试过FFmpeg网站上提供的Windows版本和编译时使用--enable-dxva2选项的版本。我已经搜索了很多,但无法找到自己做错了什么。

希望有人能帮助我,或者指向一个更好的示例?


我也在Surface Pro 3上进行了测试,该设备搭载i5 4300U @ 1.9GHz(4个CPU)、8 GB RAM、Intel HD Graphics 4400、Windows 10操作系统,视频效果良好,没有出现错误信息。与第二台计算机相比,使用硬件解码后CPU使用率降低了40%。GPU使用率仅比其他两台计算机高1%或2%,在3840x2160分辨率下测试同一视频。 - CD83
哇,这是我在SO上见过的最有用和全面的帖子之一。可惜我只能点赞一次(好吧,如果算上你的答案,就是两次)。感谢您,致敬! - user2328447
1个回答

7

我终于找到了问题所在。在调用avcodec_decode_video2之后,我没有像这样更新数据包的大小和数据指针:

int r = avcodec_decode_video2(_codecContext, frame, &frameDecoded, &pkt);
pkt.size -= r;
pkt.data += r;

现在,视频已经被正确解码,并且我不再遇到任何伪影了。
此外,关于延迟问题,我认为这是一个单独的问题,与错误信息无关,并且由于将图像复制回CPU内存所需的时间而导致。如果您需要这样做,您可以查看VLC或者参考此链接https://software.intel.com/en-us/articles/copying-accelerated-video-decode-frame-buffers,而不是像我在上面提问时发布的代码中使用av_image_copy_plane。我在我的机器上进行了快速测试,时间缩短了7到8倍。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接