Bug 1397307 - P6. Calculate average video frame rate as video is playing. r?gerald draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Tue, 12 Sep 2017 21:20:09 +0200
changeset 665096 9759e2aa9ca20240eeb0a8448a067a1f1b4c1215
parent 665095 992e96056ca923da12df20b765e44717cf894a1f
child 665097 61e18a25dbcbcf607b9412408784765bc3b85bc5
push id79919
push userbmo:jyavenard@mozilla.com
push dateThu, 14 Sep 2017 22:16:27 +0000
reviewersgerald
bugs1397307
milestone57.0a1
Bug 1397307 - P6. Calculate average video frame rate as video is playing. r?gerald We unfortunately can't store this information in the VideoInfo as typically the framerate isn't found in the container's metadata. Additionally, the VideoInfo object is readable-only as it is shared across threads. As such, we can only estimate it as we demux samples. MozReview-Commit-ID: 5HB33ubfGAs
dom/media/MediaFormatReader.cpp
dom/media/MediaFormatReader.h
dom/media/platforms/PlatformDecoderModule.h
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -742,29 +742,28 @@ MediaFormatReader::DecoderFactory::DoCre
         &mOwner->OnTrackWaitingForKeyProducer()
       });
       break;
     }
 
     case TrackType::kVideoTrack: {
       // Decoders use the layers backend to decide if they can use hardware decoding,
       // so specify LAYERS_NONE if we want to forcibly disable it.
-      aData.mDecoder = mOwner->mPlatform->CreateDecoder({
-        ownerData.mInfo
-        ? *ownerData.mInfo->GetAsVideoInfo()
-        : *ownerData.mOriginalInfo->GetAsVideoInfo(),
-        ownerData.mTaskQueue,
-        mOwner->mKnowsCompositor,
-        mOwner->GetImageContainer(),
-        mOwner->mCrashHelper,
-        CreateDecoderParams::UseNullDecoder(ownerData.mIsNullDecode),
-        &result,
-        TrackType::kVideoTrack,
-        &mOwner->OnTrackWaitingForKeyProducer()
-      });
+      aData.mDecoder = mOwner->mPlatform->CreateDecoder(
+        { ownerData.mInfo ? *ownerData.mInfo->GetAsVideoInfo()
+                          : *ownerData.mOriginalInfo->GetAsVideoInfo(),
+          ownerData.mTaskQueue,
+          mOwner->mKnowsCompositor,
+          mOwner->GetImageContainer(),
+          mOwner->mCrashHelper,
+          CreateDecoderParams::UseNullDecoder(ownerData.mIsNullDecode),
+          &result,
+          TrackType::kVideoTrack,
+          &mOwner->OnTrackWaitingForKeyProducer(),
+          CreateDecoderParams::VideoFrameRate(ownerData.mMeanRate.Mean()) });
       break;
     }
 
     default:
       break;
   }
 
   if (aData.mDecoder) {
@@ -2086,31 +2085,37 @@ MediaFormatReader::HandleDemuxedSamples(
           TrackTypeToStr(aTrack),
           decoder.mLastStreamSourceID,
           info->GetID());
 
       decoder.mNextStreamSourceID.reset();
       decoder.mLastStreamSourceID = info->GetID();
       decoder.mInfo = info;
 
+      decoder.mMeanRate.Reset();
+
       if (sample->mKeyframe) {
         if (samples.Length()) {
           decoder.mQueuedSamples = Move(samples);
         }
       } else {
         auto time = TimeInterval(sample->mTime, sample->GetEndTime());
         InternalSeekTarget seekTarget =
           decoder.mTimeThreshold.refOr(InternalSeekTarget(time, false));
         LOG("Stream change occurred on a non-keyframe. Seeking to:%" PRId64,
             sample->mTime.ToMicroseconds());
         InternalSeek(aTrack, seekTarget);
         return;
       }
     }
 
+    // Calculate the average frame rate. The first frame will be accounted
+    // for twice.
+    decoder.mMeanRate.Update(sample->mDuration);
+
     if (!decoder.mDecoder) {
       mDecoderFactory->CreateDecoder(aTrack);
       return;
     }
 
     LOGV("Input:%" PRId64 " (dts:%" PRId64 " kf:%d)",
          sample->mTime.ToMicroseconds(), sample->mTimecode.ToMicroseconds(),
          sample->mKeyframe);
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -570,16 +570,39 @@ private:
     Maybe<media::TimeUnit> mLastTimeRangesEnd;
     // TrackInfo as first discovered during ReadMetadata.
     UniquePtr<TrackInfo> mOriginalInfo;
     RefPtr<TrackInfoSharedPtr> mInfo;
     Maybe<media::TimeUnit> mFirstDemuxedSampleTime;
     // Use NullDecoderModule or not.
     bool mIsNullDecode;
 
+    class
+    {
+    public:
+      float Mean() const { return mMean; }
+
+      void Update(const media::TimeUnit& aValue)
+      {
+        if (aValue == media::TimeUnit::Zero()) {
+          return;
+        }
+        mMean += (1.0f / aValue.ToSeconds() - mMean) / ++mCount;
+      }
+
+      void Reset()
+      {
+        mMean = 0;
+        mCount = 0;
+      }
+
+    private:
+      float mMean = 0;
+      uint64_t mCount = 0;
+    } mMeanRate;
   };
 
   template <typename Type>
   class DecoderDataWithPromise : public DecoderData
   {
   public:
     DecoderDataWithPromise(MediaFormatReader* aOwner,
                            MediaData::Type aType,
--- a/dom/media/platforms/PlatformDecoderModule.h
+++ b/dom/media/platforms/PlatformDecoderModule.h
@@ -54,16 +54,23 @@ struct MOZ_STACK_CLASS CreateDecoderPara
 
   struct UseNullDecoder
   {
     UseNullDecoder() = default;
     explicit UseNullDecoder(bool aUseNullDecoder) : mUse(aUseNullDecoder) { }
     bool mUse = false;
   };
 
+  struct VideoFrameRate
+  {
+    VideoFrameRate() = default;
+    explicit VideoFrameRate(float aFramerate) : mValue(aFramerate) { }
+    float mValue = 0.0f;
+  };
+
   template <typename T1, typename... Ts>
   CreateDecoderParams(const TrackInfo& aConfig, T1&& a1, Ts&&... args)
     : mConfig(aConfig)
   {
     Set(mozilla::Forward<T1>(a1), mozilla::Forward<Ts>(args)...);
   }
 
   const VideoInfo& VideoConfig() const
@@ -92,31 +99,33 @@ struct MOZ_STACK_CLASS CreateDecoderPara
   layers::ImageContainer* mImageContainer = nullptr;
   MediaResult* mError = nullptr;
   RefPtr<layers::KnowsCompositor> mKnowsCompositor;
   RefPtr<GMPCrashHelper> mCrashHelper;
   UseNullDecoder mUseNullDecoder;
   TrackInfo::TrackType mType = TrackInfo::kUndefinedTrack;
   MediaEventProducer<TrackInfo::TrackType>* mOnWaitingForKeyEvent = nullptr;
   OptionSet mOptions = OptionSet(Option::Default);
+  VideoFrameRate mRate;
 
 private:
   void Set(TaskQueue* aTaskQueue) { mTaskQueue = aTaskQueue; }
   void Set(DecoderDoctorDiagnostics* aDiagnostics)
   {
     mDiagnostics = aDiagnostics;
   }
   void Set(layers::ImageContainer* aImageContainer)
   {
     mImageContainer = aImageContainer;
   }
   void Set(MediaResult* aError) { mError = aError; }
   void Set(GMPCrashHelper* aCrashHelper) { mCrashHelper = aCrashHelper; }
   void Set(UseNullDecoder aUseNullDecoder) { mUseNullDecoder = aUseNullDecoder; }
   void Set(OptionSet aOptions) { mOptions = aOptions; }
+  void Set(VideoFrameRate aRate) { mRate = aRate; }
   void Set(layers::KnowsCompositor* aKnowsCompositor)
   {
     mKnowsCompositor = aKnowsCompositor;
   }
   void Set(TrackInfo::TrackType aType)
   {
     mType = aType;
   }