mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-07-14 23:34:08 +00:00
deps/media-playback: Fix hw accel decode crash
When hardware accelerated decoding is enabled, sometimes it can't initialize for whatever reason, so it will fall back to software on its own. When this occurs, it will not use the hardware pixel format on the frame; instead it will defer to a standard format on the frame. So if the frame format does not match the expected format, assume software decoding. (This was also what the hw-decode.c FFmpeg example did if the format did not match the expected format)
This commit is contained in:
parent
41e9dd38fa
commit
94581952b5
31
deps/media-playback/media-playback/decode.c
vendored
31
deps/media-playback/media-playback/decode.c
vendored
|
@ -29,7 +29,8 @@ enum AVHWDeviceType hw_priority[] = {
|
|||
AV_HWDEVICE_TYPE_NONE,
|
||||
};
|
||||
|
||||
static bool has_hw_type(AVCodec *c, enum AVHWDeviceType type)
|
||||
static bool has_hw_type(AVCodec *c, enum AVHWDeviceType type,
|
||||
enum AVPixelFormat *hw_format)
|
||||
{
|
||||
for (int i = 0;; i++) {
|
||||
const AVCodecHWConfig *config = avcodec_get_hw_config(c, i);
|
||||
|
@ -38,8 +39,10 @@ static bool has_hw_type(AVCodec *c, enum AVHWDeviceType type)
|
|||
}
|
||||
|
||||
if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX &&
|
||||
config->device_type == type)
|
||||
config->device_type == type) {
|
||||
*hw_format = config->pix_fmt;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -51,7 +54,7 @@ static void init_hw_decoder(struct mp_decode *d, AVCodecContext *c)
|
|||
AVBufferRef *hw_ctx = NULL;
|
||||
|
||||
while (*priority != AV_HWDEVICE_TYPE_NONE) {
|
||||
if (has_hw_type(d->codec, *priority)) {
|
||||
if (has_hw_type(d->codec, *priority, &d->hw_format)) {
|
||||
int ret = av_hwdevice_ctx_create(&hw_ctx, *priority,
|
||||
NULL, NULL, 0);
|
||||
if (ret == 0)
|
||||
|
@ -63,6 +66,7 @@ static void init_hw_decoder(struct mp_decode *d, AVCodecContext *c)
|
|||
|
||||
if (hw_ctx) {
|
||||
c->hw_device_ctx = av_buffer_ref(hw_ctx);
|
||||
c->opaque = d;
|
||||
d->hw = true;
|
||||
}
|
||||
}
|
||||
|
@ -158,8 +162,8 @@ bool mp_decode_init(mp_media_t *m, enum AVMediaType type, bool hw)
|
|||
return false;
|
||||
}
|
||||
|
||||
d->frame = av_frame_alloc();
|
||||
if (!d->frame) {
|
||||
d->sw_frame = av_frame_alloc();
|
||||
if (!d->sw_frame) {
|
||||
blog(LOG_WARNING, "MP: Failed to allocate %s frame",
|
||||
av_get_media_type_string(type));
|
||||
return false;
|
||||
|
@ -175,7 +179,7 @@ bool mp_decode_init(mp_media_t *m, enum AVMediaType type, bool hw)
|
|||
|
||||
d->in_frame = d->hw_frame;
|
||||
} else {
|
||||
d->in_frame = d->frame;
|
||||
d->in_frame = d->sw_frame;
|
||||
}
|
||||
|
||||
if (d->codec->capabilities & CODEC_CAP_TRUNC)
|
||||
|
@ -213,9 +217,9 @@ void mp_decode_free(struct mp_decode *d)
|
|||
avcodec_close(d->decoder);
|
||||
#endif
|
||||
}
|
||||
if (d->frame) {
|
||||
av_frame_unref(d->frame);
|
||||
av_free(d->frame);
|
||||
if (d->sw_frame) {
|
||||
av_frame_unref(d->sw_frame);
|
||||
av_free(d->sw_frame);
|
||||
}
|
||||
|
||||
memset(d, 0, sizeof(*d));
|
||||
|
@ -293,13 +297,20 @@ static int decode_packet(struct mp_decode *d, int *got_frame)
|
|||
|
||||
#ifdef USE_NEW_HARDWARE_CODEC_METHOD
|
||||
if (*got_frame && ret && d->hw) {
|
||||
int err = av_hwframe_transfer_data(d->frame, d->hw_frame, 0);
|
||||
if (d->hw_frame->format != d->hw_format) {
|
||||
d->frame = d->hw_frame;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int err = av_hwframe_transfer_data(d->sw_frame, d->hw_frame, 0);
|
||||
if (err != 0) {
|
||||
ret = 0;
|
||||
*got_frame = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
d->frame = d->sw_frame;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
2
deps/media-playback/media-playback/decode.h
vendored
2
deps/media-playback/media-playback/decode.h
vendored
|
@ -64,8 +64,10 @@ struct mp_decode {
|
|||
int64_t frame_pts;
|
||||
int64_t next_pts;
|
||||
AVFrame *in_frame;
|
||||
AVFrame *sw_frame;
|
||||
AVFrame *hw_frame;
|
||||
AVFrame *frame;
|
||||
enum AVPixelFormat hw_format;
|
||||
bool got_first_keyframe;
|
||||
bool frame_ready;
|
||||
bool eof;
|
||||
|
|
Loading…
Reference in a new issue