Skip to content

Commit

Permalink
Improve error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
EIREXE committed Mar 4, 2024
1 parent 43dae27 commit 2ca8dc6
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 26 deletions.
23 changes: 13 additions & 10 deletions ffmpeg_video_stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,24 +264,27 @@ void FFmpegVideoStreamPlayback::update_internal(double p_delta) {
}
}

void FFmpegVideoStreamPlayback::load(Ref<FileAccess> p_file_access) {
Error FFmpegVideoStreamPlayback::load(Ref<FileAccess> p_file_access) {
decoder = Ref<VideoDecoder>(memnew(VideoDecoder(p_file_access)));

decoder->start_decoding();
Vector2i size = decoder->get_size();
if (decoder->get_decoder_state() != VideoDecoder::FAULTED) {
if (decoder->get_frame_format() == FFmpegFrameFormat::YUV420P) {
yuv_converter.instantiate();
yuv_converter->set_frame_size(size);
yuv_texture = yuv_converter->get_output_texture();
} else {
if (decoder->get_decoder_state() == VideoDecoder::FAULTED) {
return FAILED;
}

if (decoder->get_frame_format() == FFmpegFrameFormat::YUV420P) {
yuv_converter.instantiate();
yuv_converter->set_frame_size(size);
yuv_texture = yuv_converter->get_output_texture();
} else {
#ifdef GDEXTENSION
texture = ImageTexture::create_from_image(Image::create(size.x, size.y, false, Image::FORMAT_RGBA8));
texture = ImageTexture::create_from_image(Image::create(size.x, size.y, false, Image::FORMAT_RGBA8));
#else
texture = ImageTexture::create_from_image(Image::create_empty(size.x, size.y, false, Image::FORMAT_RGBA8));
texture = ImageTexture::create_from_image(Image::create_empty(size.x, size.y, false, Image::FORMAT_RGBA8));
#endif
}
}
return OK;
}

bool FFmpegVideoStreamPlayback::is_paused_internal() const {
Expand Down
6 changes: 4 additions & 2 deletions ffmpeg_video_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ class FFmpegVideoStreamPlayback : public VideoStreamPlayback {
static void _bind_methods(){}; // Required by GDExtension, do not remove

public:
void load(Ref<FileAccess> p_file_access);
Error load(Ref<FileAccess> p_file_access);

STREAM_FUNC_REDIRECT_0_CONST(bool, is_paused);
STREAM_FUNC_REDIRECT_1(void, update, double, p_delta);
Expand Down Expand Up @@ -160,7 +160,9 @@ class FFmpegVideoStream : public VideoStream {
}
Ref<FFmpegVideoStreamPlayback> pb;
pb.instantiate();
pb->load(fa);
if (pb->load(fa) != OK) {
return nullptr;
}
return pb;
}

Expand Down
31 changes: 19 additions & 12 deletions video_decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,9 @@ void VideoDecoder::prepare_decoding() {
}
}

void VideoDecoder::recreate_codec_context() {
Error VideoDecoder::recreate_codec_context() {
if (video_stream == nullptr) {
return;
return ERR_BUG;
}

AVCodecParameters codec_params = *video_stream->codecpar;
Expand All @@ -161,7 +161,8 @@ void VideoDecoder::recreate_codec_context() {
}
BitField<HardwareVideoDecoder> target_hw_decoders = hw_decoding_allowed ? target_hw_video_decoders : HardwareVideoDecoder::NONE;

for (const AvailableDecoderInfo &info : get_available_decoders(format_context->iformat, codec_params.codec_id, target_hw_decoders)) {
Vector<AvailableDecoderInfo> available_video_decoders = get_available_video_decoders(format_context->iformat, codec_params.codec_id, target_hw_decoders);
for (const AvailableDecoderInfo &info : available_video_decoders) {
if (video_codec_context != nullptr) {
avcodec_free_context(&video_codec_context);
}
Expand All @@ -187,29 +188,35 @@ void VideoDecoder::recreate_codec_context() {
int open_codec_result = avcodec_open2(video_codec_context, info.codec->get_codec_ptr(), nullptr);
ERR_CONTINUE_MSG(open_codec_result < 0, vformat("Error trying to open %s codec: %s", info.codec->get_codec_ptr()->name, ffmpeg_get_error_message(open_codec_result)));

print_line("Succesfully initialized decoder:", info.codec->get_codec_ptr()->name);
print_line("Succesfully initialized video decoder:", info.codec->get_codec_ptr()->name);
break;
}

ERR_FAIL_COND_V_MSG(available_video_decoders.size() == 0, ERR_UNAVAILABLE, vformat("Error creating video codec context: Unsupported codec %s", avcodec_get_name(codec_params.codec_id)));

ERR_FAIL_COND_V_MSG(video_codec_context == nullptr, ERR_CANT_CREATE, vformat("Error creating video codec context: Exhausted all available decoders for codec %s", avcodec_get_name(codec_params.codec_id)));

if (!audio_stream) {
return;
return OK;
}

codec_params = *audio_stream->codecpar;
const AVCodec *codec = avcodec_find_decoder(codec_params.codec_id);
if (codec) {
if (audio_codec_context != nullptr) {
avcodec_free_context(&audio_codec_context);
}
audio_codec_context = avcodec_alloc_context3(codec);
ERR_FAIL_COND_MSG(audio_codec_context == nullptr, vformat("Couldn't allocate codec context: %s", codec->name));
ERR_FAIL_COND_V_MSG(audio_codec_context == nullptr, FAILED, vformat("Couldn't allocate audio codec context: %s", codec->name));
audio_codec_context->pkt_timebase = audio_stream->time_base;

int param_copy_result = avcodec_parameters_to_context(audio_codec_context, audio_stream->codecpar);
ERR_FAIL_COND_MSG(param_copy_result < 0, vformat("Couldn't copy codec parameters from %s: %s", codec->name, ffmpeg_get_error_message(param_copy_result)));
ERR_FAIL_COND_V_MSG(param_copy_result < 0, FAILED, vformat("Couldn't copy codec parameters from %s: %s", codec->name, ffmpeg_get_error_message(param_copy_result)));
int open_codec_result = avcodec_open2(audio_codec_context, codec, nullptr);
ERR_FAIL_COND_MSG(open_codec_result < 0, vformat("Error trying to open %s codec: %s", codec->name, ffmpeg_get_error_message(open_codec_result)));
print_line("Succesfully initialized audio decoder:", codec->name);
ERR_FAIL_COND_V_MSG(open_codec_result < 0, ERR_CANT_OPEN, vformat("Error trying to open %s codec: %s", codec->name, ffmpeg_get_error_message(open_codec_result)));
has_audio = true;
}
return OK;
}

VideoDecoder::HardwareVideoDecoder VideoDecoder::from_av_hw_device_type(AVHWDeviceType p_device_type) {
Expand Down Expand Up @@ -732,9 +739,9 @@ void VideoDecoder::start_decoding() {
ERR_FAIL_COND_MSG(thread != nullptr, "Cannot start decoding once already started");
if (format_context == nullptr) {
prepare_decoding();
recreate_codec_context();
Error codec_context_create_error = recreate_codec_context();

if (video_stream == nullptr) {
if (video_stream == nullptr || codec_context_create_error != OK) {
decoder_state = DecoderState::FAULTED;
return;
}
Expand Down Expand Up @@ -775,7 +782,7 @@ struct AvailableDecoderInfoComparator {
}
};

Vector<VideoDecoder::AvailableDecoderInfo> VideoDecoder::get_available_decoders(const AVInputFormat *p_format, AVCodecID p_codec_id, BitField<HardwareVideoDecoder> p_target_decoders) {
Vector<VideoDecoder::AvailableDecoderInfo> VideoDecoder::get_available_video_decoders(const AVInputFormat *p_format, AVCodecID p_codec_id, BitField<HardwareVideoDecoder> p_target_decoders) {
Vector<VideoDecoder::AvailableDecoderInfo> codecs;

Ref<FFmpegCodec> first_codec;
Expand Down
4 changes: 2 additions & 2 deletions video_decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ class VideoDecoder : public RefCounted {
static int _read_packet_callback(void *p_opaque, uint8_t *p_buf, int p_buf_size);
static int64_t _stream_seek_callback(void *p_opaque, int64_t p_offset, int p_whence);
void prepare_decoding();
void recreate_codec_context();
Error recreate_codec_context();
static HardwareVideoDecoder from_av_hw_device_type(AVHWDeviceType p_device_type);

void _seek_command(double p_target_timestamp);
Expand All @@ -194,7 +194,7 @@ class VideoDecoder : public RefCounted {
};
void seek(double p_time, bool p_wait = false);
void start_decoding();
Vector<AvailableDecoderInfo> get_available_decoders(const AVInputFormat *p_format, AVCodecID p_codec_id, BitField<HardwareVideoDecoder> p_target_decoders);
Vector<AvailableDecoderInfo> get_available_video_decoders(const AVInputFormat *p_format, AVCodecID p_codec_id, BitField<HardwareVideoDecoder> p_target_decoders);
void return_frames(Vector<Ref<DecodedFrame>> p_frames);
void return_frame(Ref<DecodedFrame> p_frame);
Vector<Ref<DecodedFrame>> get_decoded_frames();
Expand Down

0 comments on commit 2ca8dc6

Please sign in to comment.