diff --git a/src/media/media_decoder.cpp b/src/media/media_decoder.cpp
index fdc54f795d233fa6e0a3fcfb03fc4236e88efd4c..d939b99a49e961e5f32127a4cd8c820be2924de3 100644
--- a/src/media/media_decoder.cpp
+++ b/src/media/media_decoder.cpp
@@ -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(),
                                                         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(
         &inputCtx_,
@@ -267,8 +267,10 @@ int MediaDecoder::setupFromVideoData()
     decoderCtx_->thread_count = std::thread::hardware_concurrency();
 
 #ifdef RING_ACCEL
-    accel_ = video::makeHardwareAccel(decoderCtx_);
-    decoderCtx_->opaque = accel_.get();
+    if (enableAccel_) {
+        accel_ = video::makeHardwareAccel(decoderCtx_);
+        decoderCtx_->opaque = accel_.get();
+    }
 #endif // RING_ACCEL
 
     // find the decoder for the video stream
@@ -334,8 +336,12 @@ MediaDecoder::decode(VideoFrame& result)
     if (frameFinished) {
         frame->format = (AVPixelFormat) correctPixFmt(frame->format);
 #if defined(RING_VIDEO) && defined(RING_ACCEL)
-        if (accel_ && !accel_->extractData(decoderCtx_, result))
-            return Status::DecodeError;
+        if (accel_) {
+            if (!accel_->hasFailed())
+                accel_->extractData(decoderCtx_, result);
+            else
+                return Status::DecodeError;
+        }
 #endif // RING_ACCEL
         if (emulateRate_ and frame->pkt_pts != AV_NOPTS_VALUE) {
             auto frame_time = getTimeBase()*(frame->pkt_pts - avStream_->start_time);
@@ -418,8 +424,15 @@ MediaDecoder::flush(VideoFrame& result)
     if (len <= 0)
         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::Success;
 }
diff --git a/src/media/video/accel.cpp b/src/media/video/accel.cpp
index 118a28e077586983c07fdefc1f0d73e6444cfd1e..636c5bac20ad1c826c4bf0e8d9c815cdb039ae4d 100644
--- a/src/media/video/accel.cpp
+++ b/src/media/video/accel.cpp
@@ -57,7 +57,7 @@ getFormatCb(AVCodecContext* codecCtx, const AVPixelFormat* formats)
         }
     }
 
-    accel->fail(true);
+    accel->fail(codecCtx, true);
     RING_WARN("Falling back to software decoding");
     codecCtx->get_format = avcodec_default_get_format;
     codecCtx->get_buffer2 = avcodec_default_get_buffer2;
@@ -80,7 +80,7 @@ allocateBufferCb(AVCodecContext* codecCtx, AVFrame* frame, int flags)
             return 0;
         }
 
-        accel->fail();
+        accel->fail(codecCtx, false);
     }
 
     return avcodec_default_get_buffer2(codecCtx, frame, flags);
@@ -140,13 +140,15 @@ HardwareAccel::HardwareAccel(const AccelInfo& info)
 }
 
 void
-HardwareAccel::fail(bool forceFallback)
+HardwareAccel::fail(AVCodecContext* codecCtx, bool forceFallback)
 {
     ++failCount_;
     if (failCount_ >= MAX_ACCEL_FAILURES || forceFallback) {
+        RING_ERR("Hardware acceleration failure");
         fallback_ = true;
         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;
     }
 }
 
diff --git a/src/media/video/accel.h b/src/media/video/accel.h
index f0507b6d22da517e69cd44bd199ef76ee26a9fe5..fd6f9083a2670edc25da2454f97feee7e1116223 100644
--- a/src/media/video/accel.h
+++ b/src/media/video/accel.h
@@ -60,7 +60,7 @@ class HardwareAccel {
         void setHeight(int height) { height_ = height; }
         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
 
     public: // must be implemented by derived classes
diff --git a/src/media/video/v4l2/vaapi.cpp b/src/media/video/v4l2/vaapi.cpp
index 6139e5abaabfe563341749d2c6806340f04527c9..3d3cec3b8d63584c0f5948031707ac8f66fa93c8 100644
--- a/src/media/video/v4l2/vaapi.cpp
+++ b/src/media/video/v4l2/vaapi.cpp
@@ -83,7 +83,7 @@ VaapiAccel::extractData(AVCodecContext* codecCtx, VideoFrame& container)
         av_frame_unref(input);
         av_frame_move_ref(input, output);
     } catch (const std::runtime_error& e) {
-        fail();
+        fail(codecCtx, false);
         RING_ERR("%s", e.what());
         return false;
     }
@@ -117,7 +117,7 @@ VaapiAccel::init(AVCodecContext* codecCtx)
         { AV_CODEC_ID_H264, h264 },
         { AV_CODEC_ID_MPEG4, mpeg4 },
         { 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;