我正在尝试让 FFMPEG 将 D3D11 2D 纹理直接输出为帧。据我了解,这实际上是可能的。这样做的原因是,我可以直接在 GPU 上解码 YUV 格式,然后显示它,而无需将其编组回 CPU。
我的问题是我无法让解码器以所需格式实际输出帧,它们始终是软件
YUV420J
.
这是因为我没有正确初始化解码器吗?或者我可能还缺少其他一些配置。
我大部分时间都在关注example,有一些细微差别:
AV_CODEC_ID_H264
av_hwdevice_ctx_init
上使用 av_hwdevice_ctx_create
。 (我试过只使用av_hwdevice_ctx_create
并得到相同的结果)av_hwframe_transfer_data
,因为我想把数据保存在GPU上作为纹理,马上显示出来这是我的初始化代码:
AVHWDeviceType type = AV_HWDEVICE_TYPE_D3D11VA;
hw_pix_fmt = AV_PIX_FMT_D3D11;
_codec = avcodec_find_decoder(AV_CODEC_ID_H264); // NOT SURE IF THIS IS THE HW SUPPORTED FMT
int i;
for (i = 0;; i++) {
const AVCodecHWConfig* config = avcodec_get_hw_config(_codec, i);
if (!config) {
fprintf(stderr, "Decoder %s does not support device type %s.\n",
_codec->name, av_hwdevice_get_type_name(type));
return;
}
if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX &&
config->device_type == type) {
hw_pix_fmt = config->pix_fmt;
break;
}
}
if (!(_codecCtx = avcodec_alloc_context3(_codec))) {
// ERROR!
return;
}
_hw_device_ctx = av_hwdevice_ctx_alloc(type);
_device_ctx = reinterpret_cast<AVHWDeviceContext*>(_hw_device_ctx->data);
_d3d11va_device_ctx = reinterpret_cast<AVD3D11VADeviceContext*>(_device_ctx->hwctx);
_d3d11va_device_ctx->device = dev;
_codecCtx->hw_device_ctx = av_buffer_ref(_hw_device_ctx);
if (av_hwdevice_ctx_init(_codecCtx->hw_device_ctx) < 0) {
return;
}
if (avcodec_open2(_codecCtx, _codec, NULL) < 0) {
return;
}
_parser = av_parser_init(_codec->id);
_packet = av_packet_alloc();
我正在做标准的事情来解码,并且知道它有效,因为我已经很好地使用了软件解码,但无论如何:
void Decoder::Load(std::vector<std::byte> data) {
int data_size = data.size();
int bytesRead = 0;
int bytesParsed = 0;
while (data_size > 0) {
bytesParsed = av_parser_parse2(
_parser,
_codecCtx,
&_packet->data,
&_packet->size,
(uint8_t*)&data[bytesRead],
data.size() - bytesRead,
AV_NOPTS_VALUE,
AV_NOPTS_VALUE,
0);
bytesRead += bytesParsed;
data_size -= bytesParsed;
if (bytesParsed < 0) {
//std::cout << "Error while parsing packet" << std::endl;
return;
}
if (_packet->size) {
int ret = avcodec_send_packet(_codecCtx, _packet);
if (ret < 0) {
//std::cout << "Error Sending Packet for Decoding" << std::endl;
return;
}
while (ret >= 0) {
AVFrame* frame = av_frame_alloc();
ret = avcodec_receive_frame(_codecCtx, frame);
if (frame->format != AV_PIX_FMT_D3D11) { // <--- THIS NEVER EVALUATES AS FALSE, IT'S ALWAYS THE YUV420J FORMAT, NOT THE HARDWARE FORMAT
break;
}
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
}
else if (ret < 0) {
//std::cout << "Error During Decoding" << std::endl;
return;
}
_frameQueue.push(frame);
}
}
}
}
./../../sources/ffmpeg/configure \
--prefix=./../../installed \
--toolchain=msvc \
--arch=x86_64 \
--enable-yasm \
--enable-asm \
--enable-shared \
--enable-dxva2 \
--enable-d3d11va \
--disable-static \
--enable-gpl \
--extra-ldflags="-LIBPATH:./../../installed/lib/" \
--extra-cflags="-I./../../installed/include/"