61879d2
diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h
61879d2
--- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h
61879d2
+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h
61879d2
@@ -146,10 +146,15 @@
61879d2
   RefPtr<ImageContainer> mImageContainer;
61879d2
   VideoInfo mInfo;
61879d2
   int mDecodedFrames;
61879d2
 #if LIBAVCODEC_VERSION_MAJOR >= 58
61879d2
   int mDecodedFramesLate;
61879d2
+  // Tracks when decode time of recent frame and averange decode time of
61879d2
+  // previous frames is bigger than frame interval,
61879d2
+  // i.e. we fail to decode in time.
61879d2
+  // We switch to SW decode when we hit HW_DECODE_LATE_FRAMES treshold.
61879d2
+  int mMissedDecodeInAverangeTime;
61879d2
 #endif
61879d2
   float mAverangeDecodeTime;
61879d2
 
61879d2
   class PtsCorrectionContext {
61879d2
    public:
61879d2
diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
61879d2
--- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
61879d2
+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
61879d2
@@ -14,10 +14,13 @@
61879d2
 #include "VPXDecoder.h"
61879d2
 #include "mozilla/layers/KnowsCompositor.h"
61879d2
 #if LIBAVCODEC_VERSION_MAJOR >= 57
61879d2
 #  include "mozilla/layers/TextureClient.h"
61879d2
 #endif
61879d2
+#if LIBAVCODEC_VERSION_MAJOR >= 58
61879d2
+#  include "mozilla/ProfilerMarkers.h"
61879d2
+#endif
61879d2
 #ifdef MOZ_WAYLAND_USE_VAAPI
61879d2
 #  include "H264.h"
61879d2
 #  include "mozilla/layers/DMABUFSurfaceImage.h"
61879d2
 #  include "mozilla/widget/DMABufLibWrapper.h"
61879d2
 #  include "FFmpegVideoFramePool.h"
61879d2
@@ -56,13 +59,14 @@
61879d2
 typedef int VAStatus;
61879d2
 #  define VA_EXPORT_SURFACE_READ_ONLY 0x0001
61879d2
 #  define VA_EXPORT_SURFACE_SEPARATE_LAYERS 0x0004
61879d2
 #  define VA_STATUS_SUCCESS 0x00000000
61879d2
 #endif
61879d2
-
61879d2
 // Use some extra HW frames for potential rendering lags.
61879d2
 #define EXTRA_HW_FRAMES 6
61879d2
+// Defines number of delayed frames until we switch back to SW decode.
61879d2
+#define HW_DECODE_LATE_FRAMES 15
61879d2
 
61879d2
 #if LIBAVCODEC_VERSION_MAJOR >= 57 && LIBAVUTIL_VERSION_MAJOR >= 56
61879d2
 #  define CUSTOMIZED_BUFFER_ALLOCATION 1
61879d2
 #endif
61879d2
 
61879d2
@@ -386,10 +390,11 @@
61879d2
       mImageContainer(aImageContainer),
61879d2
       mInfo(aConfig),
61879d2
       mDecodedFrames(0),
61879d2
 #if LIBAVCODEC_VERSION_MAJOR >= 58
61879d2
       mDecodedFramesLate(0),
61879d2
+      mMissedDecodeInAverangeTime(0),
61879d2
 #endif
61879d2
       mAverangeDecodeTime(0),
61879d2
       mLowLatency(aLowLatency) {
61879d2
   FFMPEG_LOG("FFmpegVideoDecoder::FFmpegVideoDecoder MIME %s Codec ID %d",
61879d2
              aConfig.mMimeType.get(), mCodecID);
61879d2
@@ -781,22 +786,32 @@
61879d2
   float decodeTime = (TimeStamp::Now() - aDecodeStart).ToMilliseconds();
61879d2
   mAverangeDecodeTime =
61879d2
       (mAverangeDecodeTime * (mDecodedFrames - 1) + decodeTime) /
61879d2
       mDecodedFrames;
61879d2
   FFMPEG_LOG(
61879d2
-      "  decode time %.2f ms averange decode time %.2f ms decoded frames %d\n",
61879d2
+      "Frame decode finished, time %.2f ms averange decode time %.2f ms "
61879d2
+      "decoded %d frames\n",
61879d2
       decodeTime, mAverangeDecodeTime, mDecodedFrames);
61879d2
 #if LIBAVCODEC_VERSION_MAJOR >= 58
61879d2
-  int frameDuration = mFrame->pkt_duration;
61879d2
-  if (frameDuration > 0 && frameDuration / 1000.0 < decodeTime) {
61879d2
-    mDecodedFramesLate++;
61879d2
-    FFMPEG_LOG(
61879d2
-        "  slow decode: failed to decode in time, frame duration %.2f ms, "
61879d2
-        "decode time %.2f\n",
61879d2
-        frameDuration / 1000.0, decodeTime);
61879d2
-    FFMPEG_LOG("  all decoded frames / late decoded frames %d/%d\n",
61879d2
-               mDecodedFrames, mDecodedFramesLate);
61879d2
+  if (mFrame->pkt_duration > 0) {
61879d2
+    // Switch frame duration to ms
61879d2
+    float frameDuration = mFrame->pkt_duration / 1000.0f;
61879d2
+    if (frameDuration < decodeTime) {
61879d2
+      PROFILER_MARKER_TEXT("FFmpegVideoDecoder::DoDecode", MEDIA_PLAYBACK, {},
61879d2
+                           "frame decode takes too long");
61879d2
+      mDecodedFramesLate++;
61879d2
+      if (frameDuration < mAverangeDecodeTime) {
61879d2
+        mMissedDecodeInAverangeTime++;
61879d2
+      }
61879d2
+      FFMPEG_LOG(
61879d2
+          "  slow decode: failed to decode in time, frame duration %.2f ms, "
61879d2
+          "decode time %.2f\n",
61879d2
+          frameDuration, decodeTime);
61879d2
+      FFMPEG_LOG("  frames: all decoded %d late decoded %d over averange %d\n",
61879d2
+                 mDecodedFrames, mDecodedFramesLate,
61879d2
+                 mMissedDecodeInAverangeTime);
61879d2
+    }
61879d2
   }
61879d2
 #endif
61879d2
 }
61879d2
 
61879d2
 MediaResult FFmpegVideoDecoder<LIBAV_VER>::DoDecode(
61879d2
@@ -866,10 +881,18 @@
61879d2
     decodeStart = TimeStamp::Now();
61879d2
 
61879d2
     MediaResult rv;
61879d2
 #  ifdef MOZ_WAYLAND_USE_VAAPI
61879d2
     if (IsHardwareAccelerated()) {
61879d2
+      if (mMissedDecodeInAverangeTime > HW_DECODE_LATE_FRAMES) {
61879d2
+        PROFILER_MARKER_TEXT("FFmpegVideoDecoder::DoDecode", MEDIA_PLAYBACK, {},
61879d2
+                             "Fallback to SW decode");
61879d2
+        FFMPEG_LOG("  HW decoding is slow, switch back to SW decode");
61879d2
+        return MediaResult(
61879d2
+            NS_ERROR_DOM_MEDIA_DECODE_ERR,
61879d2
+            RESULT_DETAIL("HW decoding is slow, switch back to SW decode"));
61879d2
+      }
61879d2
       rv = CreateImageVAAPI(mFrame->pkt_pos, GetFramePts(mFrame),
61879d2
                             mFrame->pkt_duration, aResults);
61879d2
       // If VA-API playback failed, just quit. Decoder is going to be restarted
61879d2
       // without VA-API.
61879d2
       if (NS_FAILED(rv)) {
61879d2
@@ -1129,11 +1152,11 @@
61879d2
 }
61879d2
 
61879d2
 MediaResult FFmpegVideoDecoder<LIBAV_VER>::CreateImageVAAPI(
61879d2
     int64_t aOffset, int64_t aPts, int64_t aDuration,
61879d2
     MediaDataDecoder::DecodedData& aResults) {
61879d2
-  FFMPEG_LOG("VA-API Got one frame output with pts=%" PRId64 "dts=%" PRId64
61879d2
+  FFMPEG_LOG("VA-API Got one frame output with pts=%" PRId64 " dts=%" PRId64
61879d2
              " duration=%" PRId64 " opaque=%" PRId64,
61879d2
              aPts, mFrame->pkt_dts, aDuration, mCodecContext->reordered_opaque);
61879d2
 
61879d2
   VADRMPRIMESurfaceDescriptor vaDesc;
61879d2
   if (!GetVAAPISurfaceDescriptor(&vaDesc)) {
61879d2