summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar ameerj2021-08-10 22:12:45 -0400
committerGravatar ameerj2021-08-16 14:40:53 -0400
commitbc3efb79cc11a98005a9c036d9474fbf9cb7042f (patch)
tree701ac4021fc689253cb71e1c5ec66a5a8b55f469
parentcmake: Add VDPAU and NVDEC support to FFmpeg (diff)
downloadyuzu-bc3efb79cc11a98005a9c036d9474fbf9cb7042f.tar.gz
yuzu-bc3efb79cc11a98005a9c036d9474fbf9cb7042f.tar.xz
yuzu-bc3efb79cc11a98005a9c036d9474fbf9cb7042f.zip
codec: Fallback to CPU decoding if no compatible GPU format is found
Diffstat (limited to '')
-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" {
17 17
18namespace Tegra { 18namespace Tegra {
19namespace { 19namespace {
20constexpr AVPixelFormat PREFERRED_GPU_FMT = AV_PIX_FMT_NV12;
21constexpr AVPixelFormat PREFERRED_CPU_FMT = AV_PIX_FMT_YUV420P;
22
20AVPixelFormat GetGpuFormat(AVCodecContext* av_codec_ctx, const AVPixelFormat* pix_fmts) { 23AVPixelFormat GetGpuFormat(AVCodecContext* av_codec_ctx, const AVPixelFormat* pix_fmts) {
21 for (const AVPixelFormat* p = pix_fmts; *p != AV_PIX_FMT_NONE; ++p) { 24 for (const AVPixelFormat* p = pix_fmts; *p != AV_PIX_FMT_NONE; ++p) {
22 if (*p == av_codec_ctx->pix_fmt) { 25 if (*p == av_codec_ctx->pix_fmt) {
@@ -24,7 +27,9 @@ AVPixelFormat GetGpuFormat(AVCodecContext* av_codec_ctx, const AVPixelFormat* pi
24 } 27 }
25 } 28 }
26 LOG_INFO(Service_NVDRV, "Could not find compatible GPU AV format, falling back to CPU"); 29 LOG_INFO(Service_NVDRV, "Could not find compatible GPU AV format, falling back to CPU");
27 return AV_PIX_FMT_NONE; 30 av_buffer_unref(&av_codec_ctx->hw_device_ctx);
31 av_codec_ctx->pix_fmt = PREFERRED_CPU_FMT;
32 return PREFERRED_CPU_FMT;
28} 33}
29} // namespace 34} // namespace
30 35
@@ -83,7 +88,12 @@ bool Codec::CreateGpuAvDevice() {
83#endif 88#endif
84 }; 89 };
85 for (const auto& type : GPU_DECODER_TYPES) { 90 for (const auto& type : GPU_DECODER_TYPES) {
86 av_hwdevice_ctx_create(&av_gpu_decoder, type, nullptr, nullptr, 0); 91 const int hwdevice_res = av_hwdevice_ctx_create(&av_gpu_decoder, type, nullptr, nullptr, 0);
92 if (hwdevice_res < 0) {
93 LOG_DEBUG(Service_NVDRV, "{} av_hwdevice_ctx_create failed {}",
94 av_hwdevice_get_type_name(type), hwdevice_res);
95 continue;
96 }
87 for (int i = 0;; i++) { 97 for (int i = 0;; i++) {
88 const AVCodecHWConfig* config = avcodec_get_hw_config(av_codec, i); 98 const AVCodecHWConfig* config = avcodec_get_hw_config(av_codec, i);
89 if (!config) { 99 if (!config) {
@@ -110,36 +120,34 @@ void Codec::InitializeGpuDecoder() {
110 ASSERT_MSG(hw_device_ctx, "av_buffer_ref failed"); 120 ASSERT_MSG(hw_device_ctx, "av_buffer_ref failed");
111 av_codec_ctx->hw_device_ctx = hw_device_ctx; 121 av_codec_ctx->hw_device_ctx = hw_device_ctx;
112 av_codec_ctx->get_format = GetGpuFormat; 122 av_codec_ctx->get_format = GetGpuFormat;
113 using_gpu_decode = true;
114} 123}
115 124
116void Codec::Initialize() { 125void Codec::Initialize() {
117 AVCodecID codec; 126 const AVCodecID codec = [&] {
118 switch (current_codec) { 127 switch (current_codec) {
119 case NvdecCommon::VideoCodec::H264: 128 case NvdecCommon::VideoCodec::H264:
120 codec = AV_CODEC_ID_H264; 129 return AV_CODEC_ID_H264;
121 break; 130 case NvdecCommon::VideoCodec::Vp9:
122 case NvdecCommon::VideoCodec::Vp9: 131 return AV_CODEC_ID_VP9;
123 codec = AV_CODEC_ID_VP9; 132 default:
124 break; 133 UNIMPLEMENTED_MSG("Unknown codec {}", current_codec);
125 default: 134 return AV_CODEC_ID_NONE;
126 UNIMPLEMENTED_MSG("Unknown codec {}", current_codec); 135 }
127 return; 136 }();
128 }
129 av_codec = avcodec_find_decoder(codec); 137 av_codec = avcodec_find_decoder(codec);
130 av_codec_ctx = avcodec_alloc_context3(av_codec); 138 av_codec_ctx = avcodec_alloc_context3(av_codec);
131 av_opt_set(av_codec_ctx->priv_data, "tune", "zerolatency", 0); 139 av_opt_set(av_codec_ctx->priv_data, "tune", "zerolatency", 0);
132 140
133 InitializeGpuDecoder(); 141 InitializeGpuDecoder();
134 if (!av_codec_ctx->hw_device_ctx) {
135 LOG_INFO(Service_NVDRV, "Using FFmpeg software decoding");
136 }
137 if (const int res = avcodec_open2(av_codec_ctx, av_codec, nullptr); res < 0) { 142 if (const int res = avcodec_open2(av_codec_ctx, av_codec, nullptr); res < 0) {
138 LOG_ERROR(Service_NVDRV, "avcodec_open2() Failed with result {}", res); 143 LOG_ERROR(Service_NVDRV, "avcodec_open2() Failed with result {}", res);
139 avcodec_close(av_codec_ctx); 144 avcodec_close(av_codec_ctx);
140 av_buffer_unref(&av_gpu_decoder); 145 av_buffer_unref(&av_gpu_decoder);
141 return; 146 return;
142 } 147 }
148 if (!av_codec_ctx->hw_device_ctx) {
149 LOG_INFO(Service_NVDRV, "Using FFmpeg software decoding");
150 }
143 initialized = true; 151 initialized = true;
144} 152}
145 153
@@ -155,6 +163,9 @@ void Codec::Decode() {
155 if (is_first_frame) { 163 if (is_first_frame) {
156 Initialize(); 164 Initialize();
157 } 165 }
166 if (!initialized) {
167 return;
168 }
158 bool vp9_hidden_frame = false; 169 bool vp9_hidden_frame = false;
159 std::vector<u8> frame_data; 170 std::vector<u8> frame_data;
160 if (current_codec == NvdecCommon::VideoCodec::H264) { 171 if (current_codec == NvdecCommon::VideoCodec::H264) {
@@ -191,18 +202,18 @@ void Codec::Decode() {
191 LOG_WARNING(Service_NVDRV, "Zero width or height in frame"); 202 LOG_WARNING(Service_NVDRV, "Zero width or height in frame");
192 return; 203 return;
193 } 204 }
194 if (using_gpu_decode) { 205 if (av_codec_ctx->hw_device_ctx) {
195 final_frame = AVFramePtr{av_frame_alloc(), AVFrameDeleter}; 206 final_frame = AVFramePtr{av_frame_alloc(), AVFrameDeleter};
196 ASSERT_MSG(final_frame, "av_frame_alloc final_frame failed"); 207 ASSERT_MSG(final_frame, "av_frame_alloc final_frame failed");
197 // Can't use AV_PIX_FMT_YUV420P and share code with software decoding in vic.cpp 208 // Can't use AV_PIX_FMT_YUV420P and share code with software decoding in vic.cpp
198 // because Intel drivers crash unless using AV_PIX_FMT_NV12 209 // because Intel drivers crash unless using AV_PIX_FMT_NV12
199 final_frame->format = AV_PIX_FMT_NV12; 210 final_frame->format = PREFERRED_GPU_FMT;
200 const int ret = av_hwframe_transfer_data(final_frame.get(), initial_frame.get(), 0); 211 const int ret = av_hwframe_transfer_data(final_frame.get(), initial_frame.get(), 0);
201 ASSERT_MSG(!ret, "av_hwframe_transfer_data error {}", ret); 212 ASSERT_MSG(!ret, "av_hwframe_transfer_data error {}", ret);
202 } else { 213 } else {
203 final_frame = std::move(initial_frame); 214 final_frame = std::move(initial_frame);
204 } 215 }
205 if (final_frame->format != AV_PIX_FMT_YUV420P && final_frame->format != AV_PIX_FMT_NV12) { 216 if (final_frame->format != PREFERRED_CPU_FMT && final_frame->format != PREFERRED_GPU_FMT) {
206 UNIMPLEMENTED_MSG("Unexpected video format: {}", final_frame->format); 217 UNIMPLEMENTED_MSG("Unexpected video format: {}", final_frame->format);
207 return; 218 return;
208 } 219 }
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:
60 bool CreateGpuAvDevice(); 60 bool CreateGpuAvDevice();
61 61
62 bool initialized{}; 62 bool initialized{};
63 bool using_gpu_decode{};
64 NvdecCommon::VideoCodec current_codec{NvdecCommon::VideoCodec::None}; 63 NvdecCommon::VideoCodec current_codec{NvdecCommon::VideoCodec::None};
65 64
66 AVCodec* av_codec{nullptr}; 65 AVCodec* av_codec{nullptr};