summaryrefslogtreecommitdiffstats
path: root/src/video_core/command_classes
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/command_classes')
-rw-r--r--src/video_core/command_classes/codecs/codec.cpp53
-rw-r--r--src/video_core/command_classes/codecs/codec.h1
2 files changed, 32 insertions, 22 deletions
diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp
index 0ad6162ca..400834129 100644
--- a/src/video_core/command_classes/codecs/codec.cpp
+++ b/src/video_core/command_classes/codecs/codec.cpp
@@ -17,6 +17,9 @@ extern "C" {
namespace Tegra {
namespace {
+constexpr AVPixelFormat PREFERRED_GPU_FMT = AV_PIX_FMT_NV12;
+constexpr AVPixelFormat PREFERRED_CPU_FMT = AV_PIX_FMT_YUV420P;
+
AVPixelFormat GetGpuFormat(AVCodecContext* av_codec_ctx, const AVPixelFormat* pix_fmts) {
for (const AVPixelFormat* p = pix_fmts; *p != AV_PIX_FMT_NONE; ++p) {
if (*p == av_codec_ctx->pix_fmt) {
@@ -24,7 +27,9 @@ AVPixelFormat GetGpuFormat(AVCodecContext* av_codec_ctx, const AVPixelFormat* pi
}
}
LOG_INFO(Service_NVDRV, "Could not find compatible GPU AV format, falling back to CPU");
- return AV_PIX_FMT_NONE;
+ av_buffer_unref(&av_codec_ctx->hw_device_ctx);
+ av_codec_ctx->pix_fmt = PREFERRED_CPU_FMT;
+ return PREFERRED_CPU_FMT;
}
} // namespace
@@ -83,7 +88,12 @@ bool Codec::CreateGpuAvDevice() {
#endif
};
for (const auto& type : GPU_DECODER_TYPES) {
- av_hwdevice_ctx_create(&av_gpu_decoder, type, nullptr, nullptr, 0);
+ const int hwdevice_res = av_hwdevice_ctx_create(&av_gpu_decoder, type, nullptr, nullptr, 0);
+ if (hwdevice_res < 0) {
+ LOG_DEBUG(Service_NVDRV, "{} av_hwdevice_ctx_create failed {}",
+ av_hwdevice_get_type_name(type), hwdevice_res);
+ continue;
+ }
for (int i = 0;; i++) {
const AVCodecHWConfig* config = avcodec_get_hw_config(av_codec, i);
if (!config) {
@@ -110,36 +120,34 @@ void Codec::InitializeGpuDecoder() {
ASSERT_MSG(hw_device_ctx, "av_buffer_ref failed");
av_codec_ctx->hw_device_ctx = hw_device_ctx;
av_codec_ctx->get_format = GetGpuFormat;
- using_gpu_decode = true;
}
void Codec::Initialize() {
- AVCodecID codec;
- switch (current_codec) {
- case NvdecCommon::VideoCodec::H264:
- codec = AV_CODEC_ID_H264;
- break;
- case NvdecCommon::VideoCodec::Vp9:
- codec = AV_CODEC_ID_VP9;
- break;
- default:
- UNIMPLEMENTED_MSG("Unknown codec {}", current_codec);
- return;
- }
+ const AVCodecID codec = [&] {
+ switch (current_codec) {
+ case NvdecCommon::VideoCodec::H264:
+ return AV_CODEC_ID_H264;
+ case NvdecCommon::VideoCodec::Vp9:
+ return AV_CODEC_ID_VP9;
+ default:
+ UNIMPLEMENTED_MSG("Unknown codec {}", current_codec);
+ return AV_CODEC_ID_NONE;
+ }
+ }();
av_codec = avcodec_find_decoder(codec);
av_codec_ctx = avcodec_alloc_context3(av_codec);
av_opt_set(av_codec_ctx->priv_data, "tune", "zerolatency", 0);
InitializeGpuDecoder();
- if (!av_codec_ctx->hw_device_ctx) {
- LOG_INFO(Service_NVDRV, "Using FFmpeg software decoding");
- }
if (const int res = avcodec_open2(av_codec_ctx, av_codec, nullptr); res < 0) {
LOG_ERROR(Service_NVDRV, "avcodec_open2() Failed with result {}", res);
avcodec_close(av_codec_ctx);
av_buffer_unref(&av_gpu_decoder);
return;
}
+ if (!av_codec_ctx->hw_device_ctx) {
+ LOG_INFO(Service_NVDRV, "Using FFmpeg software decoding");
+ }
initialized = true;
}
@@ -155,6 +163,9 @@ void Codec::Decode() {
if (is_first_frame) {
Initialize();
}
+ if (!initialized) {
+ return;
+ }
bool vp9_hidden_frame = false;
std::vector<u8> frame_data;
if (current_codec == NvdecCommon::VideoCodec::H264) {
@@ -191,18 +202,18 @@ void Codec::Decode() {
LOG_WARNING(Service_NVDRV, "Zero width or height in frame");
return;
}
- if (using_gpu_decode) {
+ if (av_codec_ctx->hw_device_ctx) {
final_frame = AVFramePtr{av_frame_alloc(), AVFrameDeleter};
ASSERT_MSG(final_frame, "av_frame_alloc final_frame failed");
// Can't use AV_PIX_FMT_YUV420P and share code with software decoding in vic.cpp
// because Intel drivers crash unless using AV_PIX_FMT_NV12
- final_frame->format = AV_PIX_FMT_NV12;
+ final_frame->format = PREFERRED_GPU_FMT;
const int ret = av_hwframe_transfer_data(final_frame.get(), initial_frame.get(), 0);
ASSERT_MSG(!ret, "av_hwframe_transfer_data error {}", ret);
} else {
final_frame = std::move(initial_frame);
}
- if (final_frame->format != AV_PIX_FMT_YUV420P && final_frame->format != AV_PIX_FMT_NV12) {
+ if (final_frame->format != PREFERRED_CPU_FMT && final_frame->format != PREFERRED_GPU_FMT) {
UNIMPLEMENTED_MSG("Unexpected video format: {}", final_frame->format);
return;
}
diff --git a/src/video_core/command_classes/codecs/codec.h b/src/video_core/command_classes/codecs/codec.h
index abfe59221..f51ab9df0 100644
--- a/src/video_core/command_classes/codecs/codec.h
+++ b/src/video_core/command_classes/codecs/codec.h
@@ -60,7 +60,6 @@ private:
bool CreateGpuAvDevice();
bool initialized{};
- bool using_gpu_decode{};
NvdecCommon::VideoCodec current_codec{NvdecCommon::VideoCodec::None};
AVCodec* av_codec{nullptr};