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
}
[[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>
enum AVPixelFormat GetFormatImplementation(
AVCodecContext *ctx,
@ -258,29 +314,8 @@ CodecPointer MakeCodecPointer(CodecDescriptor descriptor) {
return {};
}
if (descriptor.type != AV_HWDEVICE_TYPE_NONE) {
const auto hw = ResolveHwAccel(codec, descriptor.type);
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);
if (descriptor.hwAllowed) {
context->get_format = GetHwFormat;
} else {
DEBUG_LOG(("Video Info: Using software \"%2\" decoder."
).arg(codec->name));

View file

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

View file

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

View file

@ -163,36 +163,15 @@ Stream File::Context::initStream(
}
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 (info->disposition & AV_DISPOSITION_ATTACHED_PIC) {
// ignore cover streams
return Stream();
}
const auto hwAccelTypes = std::array{
#ifdef Q_OS_WIN
AV_HWDEVICE_TYPE_D3D11VA,
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;
}
}
result.codec = FFmpeg::MakeCodecPointer({
.stream = info,
.hwAllowed = hwAllowed,
});
if (!result.codec) {
return result;
}
@ -202,7 +181,9 @@ Stream File::Context::initStream(
result.frequency = info->codecpar->sample_rate;
if (!result.frequency) {
return result;
} else if (!tryCreateCodec(AV_HWDEVICE_TYPE_NONE)) {
}
result.codec = FFmpeg::MakeCodecPointer({ .stream = info });
if (!result.codec) {
return result;
}
}

View file

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

View file

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

View file

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