Fix fallback to software decoding in FFmpeg.

This commit is contained in:
John Preston 2022-03-30 12:20:44 +04:00
parent 528a3cdca1
commit e8748986bf
7 changed files with 70 additions and 54 deletions

View file

@ -85,6 +85,62 @@ void PremultiplyLine(uchar *dst, const uchar *src, int intsCount) {
#endif // LIB_FFMPEG_USE_QT_PRIVATE_API #endif // LIB_FFMPEG_USE_QT_PRIVATE_API
} }
[[nodiscard]] bool InitHw(AVCodecContext *context, AVHWDeviceType type) {
auto hwDeviceContext = (AVBufferRef*)nullptr;
AvErrorWrap error = av_hwdevice_ctx_create(
&hwDeviceContext,
type,
nullptr,
nullptr,
0);
if (error || !hwDeviceContext) {
LogError(qstr("av_hwdevice_ctx_create"), error);
return false;
}
DEBUG_LOG(("Video Info: "
"Trying \"%1\" hardware acceleration for \"%2\" decoder."
).arg(av_hwdevice_get_type_name(type)
).arg(context->codec->name));
if (context->hw_device_ctx) {
av_buffer_unref(&context->hw_device_ctx);
}
context->hw_device_ctx = av_buffer_ref(hwDeviceContext);
av_buffer_unref(&hwDeviceContext);
return true;
}
[[nodiscard]] enum AVPixelFormat GetHwFormat(
AVCodecContext *context,
const enum AVPixelFormat *formats) {
const enum AVPixelFormat *p = nullptr;
for (p = formats; *p != AV_PIX_FMT_NONE; p++) {
const auto type = [&] {
switch (*p) {
#ifdef Q_OS_WIN
case AV_PIX_FMT_D3D11: return AV_HWDEVICE_TYPE_D3D11VA;
case AV_PIX_FMT_DXVA2_VLD: return AV_HWDEVICE_TYPE_DXVA2;
case AV_PIX_FMT_D3D11VA_VLD: return AV_HWDEVICE_TYPE_D3D11VA;
#elif defined Q_OS_MAC // Q_OS_WIN
case AV_PIX_FMT_VIDEOTOOLBOX:
return AV_HWDEVICE_TYPE_VIDEOTOOLBOX;
#else // Q_OS_WIN || Q_OS_MAC
case AV_PIX_FMT_VAAPI: return AV_HWDEVICE_TYPE_VAAPI;
case AV_PIX_FMT_VDPAU: return AV_HWDEVICE_TYPE_VDPAU;
#endif // Q_OS_WIN || Q_OS_MAC
case AV_PIX_FMT_CUDA: return AV_HWDEVICE_TYPE_CUDA;
}
return AV_HWDEVICE_TYPE_NONE;
}();
if (type != AV_HWDEVICE_TYPE_NONE && !InitHw(context, type)) {
continue;
} else if (type == AV_HWDEVICE_TYPE_NONE && context->hw_device_ctx) {
av_buffer_unref(&context->hw_device_ctx);
}
return *p;
}
return AV_PIX_FMT_NONE;
}
template <AVPixelFormat Required> template <AVPixelFormat Required>
enum AVPixelFormat GetFormatImplementation( enum AVPixelFormat GetFormatImplementation(
AVCodecContext *ctx, AVCodecContext *ctx,
@ -258,29 +314,8 @@ CodecPointer MakeCodecPointer(CodecDescriptor descriptor) {
return {}; return {};
} }
if (descriptor.type != AV_HWDEVICE_TYPE_NONE) { if (descriptor.hwAllowed) {
const auto hw = ResolveHwAccel(codec, descriptor.type); context->get_format = GetHwFormat;
if (!hw.getFormat) {
return {};
}
context->get_format = hw.getFormat;
auto hwDeviceContext = (AVBufferRef*)nullptr;
error = av_hwdevice_ctx_create(
&hwDeviceContext,
descriptor.type,
nullptr,
nullptr,
0);
if (error || !hwDeviceContext) {
LogError(qstr("av_hwdevice_ctx_create"), error);
return {};
}
DEBUG_LOG(("Video Info: "
"Using \"%1\" hardware acceleration for \"%2\" decoder."
).arg(av_hwdevice_get_type_name(descriptor.type)
).arg(codec->name));
context->hw_device_ctx = av_buffer_ref(hwDeviceContext);
av_buffer_unref(&hwDeviceContext);
} else { } else {
DEBUG_LOG(("Video Info: Using software \"%2\" decoder." DEBUG_LOG(("Video Info: Using software \"%2\" decoder."
).arg(codec->name)); ).arg(codec->name));

View file

@ -128,7 +128,7 @@ using CodecPointer = std::unique_ptr<AVCodecContext, CodecDeleter>;
struct CodecDescriptor { struct CodecDescriptor {
not_null<AVStream*> stream; not_null<AVStream*> stream;
AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE; bool hwAllowed = false;
}; };
[[nodiscard]] CodecPointer MakeCodecPointer(CodecDescriptor descriptor); [[nodiscard]] CodecPointer MakeCodecPointer(CodecDescriptor descriptor);

View file

@ -45,7 +45,7 @@ struct PlaybackOptions {
AudioMsgId audioId; AudioMsgId audioId;
bool syncVideoByAudio = true; bool syncVideoByAudio = true;
bool waitForMarkAsShown = false; bool waitForMarkAsShown = false;
bool hwAllow = false; bool hwAllowed = false;
bool loop = false; bool loop = false;
}; };

View file

@ -163,36 +163,15 @@ Stream File::Context::initStream(
} }
const auto info = format->streams[index]; const auto info = format->streams[index];
const auto tryCreateCodec = [&](AVHWDeviceType type) {
result.codec = FFmpeg::MakeCodecPointer({
.stream = info,
.type = type,
});
return (result.codec != nullptr);
};
if (type == AVMEDIA_TYPE_VIDEO) { if (type == AVMEDIA_TYPE_VIDEO) {
if (info->disposition & AV_DISPOSITION_ATTACHED_PIC) { if (info->disposition & AV_DISPOSITION_ATTACHED_PIC) {
// ignore cover streams // ignore cover streams
return Stream(); return Stream();
} }
const auto hwAccelTypes = std::array{ result.codec = FFmpeg::MakeCodecPointer({
#ifdef Q_OS_WIN .stream = info,
AV_HWDEVICE_TYPE_D3D11VA, .hwAllowed = hwAllowed,
AV_HWDEVICE_TYPE_DXVA2, });
#elif defined Q_OS_MAC // Q_OS_WIN
AV_HWDEVICE_TYPE_VIDEOTOOLBOX,
#else // Q_OS_WIN || Q_OS_MAC
AV_HWDEVICE_TYPE_VAAPI,
AV_HWDEVICE_TYPE_VDPAU,
#endif // Q_OS_WIN || Q_OS_MAC
AV_HWDEVICE_TYPE_CUDA,
AV_HWDEVICE_TYPE_NONE,
};
for (const auto type : hwAccelTypes) {
if (tryCreateCodec(type)) {
break;
}
}
if (!result.codec) { if (!result.codec) {
return result; return result;
} }
@ -202,7 +181,9 @@ Stream File::Context::initStream(
result.frequency = info->codecpar->sample_rate; result.frequency = info->codecpar->sample_rate;
if (!result.frequency) { if (!result.frequency) {
return result; return result;
} else if (!tryCreateCodec(AV_HWDEVICE_TYPE_NONE)) { }
result.codec = FFmpeg::MakeCodecPointer({ .stream = info });
if (!result.codec) {
return result; return result;
} }
} }

View file

@ -544,7 +544,7 @@ void Player::play(const PlaybackOptions &options) {
_options.speed = 1.; _options.speed = 1.;
} }
_stage = Stage::Initializing; _stage = Stage::Initializing;
_file->start(delegate(), _options.position, _options.hwAllow); _file->start(delegate(), _options.position, _options.hwAllowed);
} }
void Player::savePreviousReceivedTill( void Player::savePreviousReceivedTill(

View file

@ -3116,7 +3116,7 @@ void OverlayWidget::restartAtSeekPosition(crl::time position) {
} }
auto options = Streaming::PlaybackOptions(); auto options = Streaming::PlaybackOptions();
options.position = position; options.position = position;
options.hwAllow = true; options.hwAllowed = true;
if (!_streamed->withSound) { if (!_streamed->withSound) {
options.mode = Streaming::Mode::Video; options.mode = Streaming::Mode::Video;
options.loop = true; options.loop = true;

View file

@ -1604,7 +1604,7 @@ void Pip::restartAtSeekPosition(crl::time position) {
auto options = Streaming::PlaybackOptions(); auto options = Streaming::PlaybackOptions();
options.position = position; options.position = position;
options.hwAllow = true; options.hwAllowed = true;
options.audioId = _instance.player().prepareLegacyState().id; options.audioId = _instance.player().prepareLegacyState().id;
Assert(8 && _delegate->pipPlaybackSpeed() >= 0.5 Assert(8 && _delegate->pipPlaybackSpeed() >= 0.5