diff --git a/deps/media-playback/media-playback/decode.c b/deps/media-playback/media-playback/decode.c index 2a13e9b8b..7f7d26095 100644 --- a/deps/media-playback/media-playback/decode.c +++ b/deps/media-playback/media-playback/decode.c @@ -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; } diff --git a/deps/media-playback/media-playback/decode.h b/deps/media-playback/media-playback/decode.h index f7168124a..1d0b7e395 100644 --- a/deps/media-playback/media-playback/decode.h +++ b/deps/media-playback/media-playback/decode.h @@ -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;