diff --git a/src/media/media_decoder.cpp b/src/media/media_decoder.cpp index 989e0ac898fd8db74c1c63822b844a5da776a5bd..0512111a5cf905f8c6cf912d7fe81395ac7b07a9 100644 --- a/src/media/media_decoder.cpp +++ b/src/media/media_decoder.cpp @@ -363,19 +363,33 @@ MediaDecoder::decode(VideoFrame& result) int frameFinished = 0; #if LIBAVCODEC_VERSION_CHECK(57, 25, 0, 48, 101) ret = avcodec_send_packet(decoderCtx_, &inpacket); - if (ret < 0) + if (ret < 0) { +#ifdef RING_ACCEL + if (accel_->hasFailed()) + return Status::RestartRequired; +#endif return ret == AVERROR_EOF ? Status::Success : Status::DecodeError; - + } ret = avcodec_receive_frame(decoderCtx_, frame); - if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) + if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) { +#ifdef RING_ACCEL + if (accel_->hasFailed()) + return Status::RestartRequired; +#endif return Status::DecodeError; + } if (ret >= 0) frameFinished = 1; #else ret = avcodec_decode_video2(decoderCtx_, frame, &frameFinished, &inpacket); - if (ret <= 0) + if (ret <= 0) { +#ifdef RING_ACCEL + if (accel_->hasFailed()) + return Status::RestartRequired; +#endif return Status::DecodeError; + } #endif av_packet_unref(&inpacket); diff --git a/src/media/video/accel.cpp b/src/media/video/accel.cpp index bf4ff124291d86114a5460f28f92d134a505c2a0..5bd9dc49857ac8b7438bdfbec61bbce9754d4cec 100644 --- a/src/media/video/accel.cpp +++ b/src/media/video/accel.cpp @@ -81,11 +81,11 @@ allocateBufferCb(AVCodecContext* codecCtx, AVFrame* frame, int flags) { if (auto accel = static_cast<HardwareAccel*>(codecCtx->opaque)) { if (!accel->hasFailed() && accel->allocateBuffer(frame, flags) == 0) { - accel->succeed(); + accel->succeedAllocation(); return 0; } - accel->fail(false); + accel->failAllocation(); } return avcodec_default_get_buffer2(codecCtx, frame, flags); @@ -96,14 +96,28 @@ HardwareAccel::HardwareAccel(const std::string& name, const AVPixelFormat format , format_(format) {} +void +HardwareAccel::failAllocation() +{ + ++allocationFails_; + fail(false); +} + +void +HardwareAccel::failExtraction() +{ + ++extractionFails_; + fail(false); +} + void HardwareAccel::fail(bool forceFallback) { - ++failCount_; - if (failCount_ >= MAX_ACCEL_FAILURES || forceFallback) { + if (allocationFails_ >= MAX_ACCEL_FAILURES || extractionFails_ >= MAX_ACCEL_FAILURES || forceFallback) { RING_ERR("Hardware acceleration failure"); fallback_ = true; - failCount_ = 0; + allocationFails_ = 0; + extractionFails_ = 0; codecCtx_->get_format = avcodec_default_get_format; codecCtx_->get_buffer2 = avcodec_default_get_buffer2; } @@ -135,12 +149,12 @@ HardwareAccel::extractData(VideoFrame& input) av_frame_unref(inFrame); av_frame_move_ref(inFrame, outFrame); } catch (const std::runtime_error& e) { - fail(false); + failExtraction(); RING_ERR("%s", e.what()); return false; } - succeed(); + succeedExtraction(); return true; } diff --git a/src/media/video/accel.h b/src/media/video/accel.h index d33864706254b324a1a6e4e22c58397dc60a22fe..265f6d379eefb3eb28c56e8fd63cc050179a6531 100644 --- a/src/media/video/accel.h +++ b/src/media/video/accel.h @@ -43,8 +43,11 @@ class HardwareAccel { void setHeight(int height) { height_ = height; } void setProfile(int profile) { profile_ = profile; } + void failAllocation(); + void failExtraction(); void fail(bool forceFallback); - void succeed() { failCount_ = 0; } // call on success of allocateBuffer or extractData + void succeedAllocation() { allocationFails_ = 0; } + void succeedExtraction() { extractionFails_ = 0; } // wrapper to take care of boilerplate before calling the derived class's implementation bool extractData(VideoFrame& input); @@ -59,8 +62,9 @@ class HardwareAccel { AVCodecContext* codecCtx_ = nullptr; std::string name_; AVPixelFormat format_; - unsigned failCount_ = 0; // how many failures in a row, reset on success - bool fallback_ = false; // true when failCount_ exceeds a certain number + unsigned allocationFails_ = 0; // how many times in a row allocateBuffer has failed + unsigned extractionFails_ = 0; // how many times in a row extractData has failed + bool fallback_ = false; // set to true when successive failures exceeds MAX_ACCEL_FAILURES int width_ = -1; int height_ = -1; int profile_ = -1;