diff --git a/video_decoder.cpp b/video_decoder.cpp index d8cea8a..b40b5e5 100644 --- a/video_decoder.cpp +++ b/video_decoder.cpp @@ -124,14 +124,37 @@ void VideoDecoder::prepare_decoding() { ERR_FAIL_COND_MSG(find_stream_info_result < 0, vformat("Error finding stream info: %s", ffmpeg_get_error_message(find_stream_info_result))); int stream_index = av_find_best_stream(format_context, AVMEDIA_TYPE_VIDEO, -1, -1, (const AVCodec **)&codec, 0); + + // The stream was found but FFmpeg has no decoder for its codec. + // Re-probe ignoring decoder availability so we can name the codec and try a fallback. + if (stream_index == AVERROR_DECODER_NOT_FOUND && format_context->video_codec == nullptr) { + int raw_stream_index = av_find_best_stream(format_context, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0); + if (raw_stream_index >= 0) { + const AVCodecID unsupported_id = format_context->streams[raw_stream_index]->codecpar->codec_id; + String fallback_name = _codec_id_to_preferred_decoder_name(unsupported_id); + if (!fallback_name.is_empty()) { + forced_video_codec = avcodec_find_decoder_by_name(fallback_name.utf8().get_data()); + if (forced_video_codec != nullptr) { + print_line(vformat("No default decoder for '%s', retrying with '%s'.", + avcodec_get_name(unsupported_id), fallback_name)); + avformat_close_input(&format_context); + prepare_decoding(); + return; + } + } + ERR_FAIL_MSG(vformat("No decoder found for '%s': codec not supported by this FFmpeg build.", + avcodec_get_name(unsupported_id))); + } + } + ERR_FAIL_COND_MSG(stream_index < 0, vformat("Couldn't find video stream: %s", ffmpeg_get_error_message(stream_index))); { if (format_context->video_codec == nullptr) { const AVCodecID codec_id = format_context->streams[stream_index]->codecpar->codec_id; - String libvpx_decoder_name = _codec_id_to_libvpx(codec_id); - if (!libvpx_decoder_name.is_empty()) { - forced_video_codec = avcodec_find_decoder_by_name(libvpx_decoder_name.utf8().get_data()); + String preferred_decoder_name = _codec_id_to_preferred_decoder_name(codec_id); + if (!preferred_decoder_name.is_empty()) { + forced_video_codec = avcodec_find_decoder_by_name(preferred_decoder_name.utf8().get_data()); if (forced_video_codec != nullptr) { avformat_close_input(&format_context); prepare_decoding(); @@ -638,19 +661,24 @@ AVFrame *VideoDecoder::_ensure_frame_audio_format(AVFrame *p_frame, AVSampleForm return out_frame; } -String VideoDecoder::_codec_id_to_libvpx(AVCodecID p_codec_id) const { - String out; +String VideoDecoder::_codec_id_to_preferred_decoder_name(AVCodecID p_codec_id) const { switch (p_codec_id) { case AVCodecID::AV_CODEC_ID_VP8: { - out = "libvpx"; + return "libvpx"; } break; case AVCodecID::AV_CODEC_ID_VP9: { - out = "libvpx-vp9"; - } + return "libvpx-vp9"; + } break; + case AVCodecID::AV_CODEC_ID_HEVC: { + return "hevc"; + } break; + case AVCodecID::AV_CODEC_ID_AV1: { + return "libaom-av1"; + } break; default: { } break; } - return out; + return String(); } void VideoDecoder::seek(double p_time, bool p_wait) { diff --git a/video_decoder.h b/video_decoder.h index 04137da..acfaf49 100644 --- a/video_decoder.h +++ b/video_decoder.h @@ -191,7 +191,7 @@ class VideoDecoder : public RefCounted { Ref _ensure_frame_pixel_format(Ref p_frame, AVPixelFormat p_target_pixel_format); Ref _unwrap_yuv_frame(double p_frame_time, Ref p_frame, FFmpegFrameFormat p_out_format); AVFrame *_ensure_frame_audio_format(AVFrame *p_frame, AVSampleFormat p_target_audio_format); - String _codec_id_to_libvpx(AVCodecID p_codec_id) const; + String _codec_id_to_preferred_decoder_name(AVCodecID p_codec_id) const; public: struct AvailableDecoderInfo {