Skip to content
Snippets Groups Projects
Commit 274049bc authored by Philippe Gorley's avatar Philippe Gorley Committed by gerrit2
Browse files

video: fix hardware acceleration bugs

Now correctly takes into account user setting. Will no longer try
to retrieve data from the GPU buffer if acceleration has failed.
Uses hardware acceleration when flushing the video stream.

Change-Id: Id7787a181b3822e8c7da0e8c2ce2cdfa302a3ddd
(cherry picked from commit c49f1368)
parent bad31c23
Branches
No related tags found
No related merge requests found
...@@ -96,7 +96,7 @@ int MediaDecoder::openInput(const DeviceParams& params) ...@@ -96,7 +96,7 @@ int MediaDecoder::openInput(const DeviceParams& params)
RING_DBG("Trying to open device %s with format %s, pixel format %s, size %dx%d, rate %lf", params.input.c_str(), RING_DBG("Trying to open device %s with format %s, pixel format %s, size %dx%d, rate %lf", params.input.c_str(),
params.format.c_str(), params.pixel_format.c_str(), params.width, params.height, params.framerate.real()); params.format.c_str(), params.pixel_format.c_str(), params.width, params.height, params.framerate.real());
enableAccel_ = (params.enableAccel == "1"); enableAccel_ = (params.enableAccel != "0");
int ret = avformat_open_input( int ret = avformat_open_input(
&inputCtx_, &inputCtx_,
...@@ -267,8 +267,10 @@ int MediaDecoder::setupFromVideoData() ...@@ -267,8 +267,10 @@ int MediaDecoder::setupFromVideoData()
decoderCtx_->thread_count = std::thread::hardware_concurrency(); decoderCtx_->thread_count = std::thread::hardware_concurrency();
#ifdef RING_ACCEL #ifdef RING_ACCEL
if (enableAccel_) {
accel_ = video::makeHardwareAccel(decoderCtx_); accel_ = video::makeHardwareAccel(decoderCtx_);
decoderCtx_->opaque = accel_.get(); decoderCtx_->opaque = accel_.get();
}
#endif // RING_ACCEL #endif // RING_ACCEL
// find the decoder for the video stream // find the decoder for the video stream
...@@ -334,8 +336,12 @@ MediaDecoder::decode(VideoFrame& result) ...@@ -334,8 +336,12 @@ MediaDecoder::decode(VideoFrame& result)
if (frameFinished) { if (frameFinished) {
frame->format = (AVPixelFormat) correctPixFmt(frame->format); frame->format = (AVPixelFormat) correctPixFmt(frame->format);
#if defined(RING_VIDEO) && defined(RING_ACCEL) #if defined(RING_VIDEO) && defined(RING_ACCEL)
if (accel_ && !accel_->extractData(decoderCtx_, result)) if (accel_) {
if (!accel_->hasFailed())
accel_->extractData(decoderCtx_, result);
else
return Status::DecodeError; return Status::DecodeError;
}
#endif // RING_ACCEL #endif // RING_ACCEL
if (emulateRate_ and frame->pkt_pts != AV_NOPTS_VALUE) { if (emulateRate_ and frame->pkt_pts != AV_NOPTS_VALUE) {
auto frame_time = getTimeBase()*(frame->pkt_pts - avStream_->start_time); auto frame_time = getTimeBase()*(frame->pkt_pts - avStream_->start_time);
...@@ -418,8 +424,15 @@ MediaDecoder::flush(VideoFrame& result) ...@@ -418,8 +424,15 @@ MediaDecoder::flush(VideoFrame& result)
if (len <= 0) if (len <= 0)
return Status::DecodeError; return Status::DecodeError;
if (frameFinished) if (frameFinished) {
#ifdef RING_ACCEL
// flush is called when closing the stream
// so don't restart the media decoder
if (accel_ && !accel_->hasFailed())
accel_->extractData(decoderCtx_, result);
#endif // RING_ACCEL
return Status::FrameFinished; return Status::FrameFinished;
}
return Status::Success; return Status::Success;
} }
......
...@@ -57,7 +57,7 @@ getFormatCb(AVCodecContext* codecCtx, const AVPixelFormat* formats) ...@@ -57,7 +57,7 @@ getFormatCb(AVCodecContext* codecCtx, const AVPixelFormat* formats)
} }
} }
accel->fail(true); accel->fail(codecCtx, true);
RING_WARN("Falling back to software decoding"); RING_WARN("Falling back to software decoding");
codecCtx->get_format = avcodec_default_get_format; codecCtx->get_format = avcodec_default_get_format;
codecCtx->get_buffer2 = avcodec_default_get_buffer2; codecCtx->get_buffer2 = avcodec_default_get_buffer2;
...@@ -80,7 +80,7 @@ allocateBufferCb(AVCodecContext* codecCtx, AVFrame* frame, int flags) ...@@ -80,7 +80,7 @@ allocateBufferCb(AVCodecContext* codecCtx, AVFrame* frame, int flags)
return 0; return 0;
} }
accel->fail(); accel->fail(codecCtx, false);
} }
return avcodec_default_get_buffer2(codecCtx, frame, flags); return avcodec_default_get_buffer2(codecCtx, frame, flags);
...@@ -140,13 +140,15 @@ HardwareAccel::HardwareAccel(const AccelInfo& info) ...@@ -140,13 +140,15 @@ HardwareAccel::HardwareAccel(const AccelInfo& info)
} }
void void
HardwareAccel::fail(bool forceFallback) HardwareAccel::fail(AVCodecContext* codecCtx, bool forceFallback)
{ {
++failCount_; ++failCount_;
if (failCount_ >= MAX_ACCEL_FAILURES || forceFallback) { if (failCount_ >= MAX_ACCEL_FAILURES || forceFallback) {
RING_ERR("Hardware acceleration failure");
fallback_ = true; fallback_ = true;
failCount_ = 0; failCount_ = 0;
// force reinit of media decoder to correctly set thread count codecCtx->get_format = avcodec_default_get_format;
codecCtx->get_buffer2 = avcodec_default_get_buffer2;
} }
} }
......
...@@ -60,7 +60,7 @@ class HardwareAccel { ...@@ -60,7 +60,7 @@ class HardwareAccel {
void setHeight(int height) { height_ = height; } void setHeight(int height) { height_ = height; }
void setProfile(int profile) { profile_ = profile; } void setProfile(int profile) { profile_ = profile; }
void fail(bool forceFallback = false); void fail(AVCodecContext* codecCtx, bool forceFallback);
void succeed() { failCount_ = 0; } // call on success of allocateBuffer or extractData void succeed() { failCount_ = 0; } // call on success of allocateBuffer or extractData
public: // must be implemented by derived classes public: // must be implemented by derived classes
......
...@@ -83,7 +83,7 @@ VaapiAccel::extractData(AVCodecContext* codecCtx, VideoFrame& container) ...@@ -83,7 +83,7 @@ VaapiAccel::extractData(AVCodecContext* codecCtx, VideoFrame& container)
av_frame_unref(input); av_frame_unref(input);
av_frame_move_ref(input, output); av_frame_move_ref(input, output);
} catch (const std::runtime_error& e) { } catch (const std::runtime_error& e) {
fail(); fail(codecCtx, false);
RING_ERR("%s", e.what()); RING_ERR("%s", e.what());
return false; return false;
} }
...@@ -117,7 +117,7 @@ VaapiAccel::init(AVCodecContext* codecCtx) ...@@ -117,7 +117,7 @@ VaapiAccel::init(AVCodecContext* codecCtx)
{ AV_CODEC_ID_H264, h264 }, { AV_CODEC_ID_H264, h264 },
{ AV_CODEC_ID_MPEG4, mpeg4 }, { AV_CODEC_ID_MPEG4, mpeg4 },
{ AV_CODEC_ID_H263, h263 }, { AV_CODEC_ID_H263, h263 },
{ AV_CODEC_ID_H263P, h263 } // no clue if this'll work, #ffmpeg isn't answering me { AV_CODEC_ID_H263P, h263 }
}; };
VAStatus status; VAStatus status;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment