Bug 951496 - Statistics data for checking the status of codec. r=jesup
authorSteven Lee <slee@mozilla.com>
Wed, 04 Jun 2014 23:56:30 -0400
changeset 207797 6dd8777a4453b583b406b486e213aefc3da0967a
parent 207796 99dc3a6c843253ee0371704cbde4e04dfafc69a4
child 207798 e30a256cb1fc14f1583c0fa3db9b4df7b16323f3
push id494
push userraliiev@mozilla.com
push dateMon, 25 Aug 2014 18:42:16 +0000
treeherdermozilla-release@a3cc3e46b571 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup
bugs951496
milestone32.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 951496 - Statistics data for checking the status of codec. r=jesup
media/webrtc/moz.build
media/webrtc/signaling/signaling.gyp
media/webrtc/signaling/src/media-conduit/CodecStatistics.cpp
media/webrtc/signaling/src/media-conduit/CodecStatistics.h
media/webrtc/signaling/src/media-conduit/RunningStat.h
media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
media/webrtc/signaling/src/media-conduit/VideoConduit.h
--- a/media/webrtc/moz.build
+++ b/media/webrtc/moz.build
@@ -57,16 +57,17 @@ if CONFIG['MOZ_WEBRTC_SIGNALING']:
         'signaling/src/sipcc/core/gsm/lsm.c',        # Because of name clash in the logTag variable
         'signaling/src/sipcc/core/sdp/sdp_base64.c', # Because of name clash with the macro PADDING
     ]
     # These files cannot be built in unified mode because they force NSPR logging.
     signaling_non_unified_sources_2 = [
         'signaling/src/callcontrol/CallControlManagerImpl.cpp',
         'signaling/src/common/browser_logging/CSFLog.cpp',
         'signaling/src/media-conduit/AudioConduit.cpp',
+        'signaling/src/media-conduit/CodecStatistics.cpp',
         'signaling/src/media-conduit/VideoConduit.cpp',
         'signaling/src/media/CSFAudioControlWrapper.cpp',
         'signaling/src/media/CSFVideoControlWrapper.cpp',
         'signaling/src/media/VcmSIPCCBinding.cpp',
         'signaling/src/mediapipeline/MediaPipeline.cpp',
         'signaling/src/mediapipeline/MediaPipelineFilter.cpp',
         'signaling/src/mediapipeline/SrtpFlow.cpp',
         'signaling/src/peerconnection/MediaStreamList.cpp',
--- a/media/webrtc/signaling/signaling.gyp
+++ b/media/webrtc/signaling/signaling.gyp
@@ -79,16 +79,19 @@
       # SOURCES
       #
       'sources': [
         # Media Conduit
         './src/media-conduit/AudioConduit.h',
         './src/media-conduit/AudioConduit.cpp',
         './src/media-conduit/VideoConduit.h',
         './src/media-conduit/VideoConduit.cpp',
+        './src/media-conduit/CodecStatistics.h',
+        './src/media-conduit/CodecStatistics.cpp',
+        './src/media-conduit/RunningStat.h',
         # Common
         './src/common/CommonTypes.h',
         './src/common/csf_common.h',
         './src/common/NullDeleter.h',
         './src/common/Wrapper.h',
         './src/common/NullTransport.h',
         './src/common/YuvStamper.cpp',
         # Browser Logging
new file mode 100644
--- /dev/null
+++ b/media/webrtc/signaling/src/media-conduit/CodecStatistics.cpp
@@ -0,0 +1,87 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "CodecStatistics.h"
+
+#include "CSFLog.h"
+
+using namespace mozilla;
+using namespace webrtc;
+
+// use the same tag as VideoConduit
+static const char* logTag ="WebrtcVideoSessionConduit";
+
+VideoCodecStatistics::VideoCodecStatistics(int channel, ViECodec* codec) :
+  mChannel(channel),
+  mSentRawFrames(0),
+  mPtrViECodec(codec),
+  mEncoderDroppedFrames(0),
+  mDecoderDiscardedPackets(0)
+{
+  MOZ_ASSERT(mPtrViECodec);
+  mPtrViECodec->RegisterEncoderObserver(mChannel, *this);
+  mPtrViECodec->RegisterDecoderObserver(mChannel, *this);
+}
+
+VideoCodecStatistics::~VideoCodecStatistics()
+{
+  mPtrViECodec->DeregisterEncoderObserver(mChannel);
+  mPtrViECodec->DeregisterDecoderObserver(mChannel);
+}
+
+void VideoCodecStatistics::OutgoingRate(const int video_channel,
+                                        const uint32_t framerate,
+                                        const uint32_t bitrate)
+{
+  unsigned int keyFrames, deltaFrames;
+  mPtrViECodec->GetSendCodecStatistics(video_channel, keyFrames, deltaFrames);
+  uint32_t dropped = mSentRawFrames - (keyFrames + deltaFrames);
+  CSFLogDebug(logTag,
+              "encoder statistics - framerate: %u, bitrate: %u, dropped frames: %u",
+              framerate, bitrate, dropped);
+  mEncoderBitRate.Push(bitrate);
+  mEncoderFps.Push(framerate);
+  mEncoderDroppedFrames += dropped;
+}
+
+void VideoCodecStatistics::IncomingCodecChanged(const int video_channel,
+                                                const VideoCodec& video_codec)
+{
+  CSFLogDebug(logTag,
+              "channel %d change codec to \"%s\" ",
+              video_channel, video_codec.plName);
+}
+
+void VideoCodecStatistics::IncomingRate(const int video_channel,
+                                        const unsigned int framerate,
+                                        const unsigned int bitrate)
+{
+  unsigned int discarded = mPtrViECodec->GetDiscardedPackets(video_channel);
+  CSFLogDebug(logTag,
+      "decoder statistics - framerate: %u, bitrate: %u, discarded packets %u",
+      framerate, bitrate, discarded);
+  mDecoderBitRate.Push(bitrate);
+  mDecoderFps.Push(framerate);
+  mDecoderDiscardedPackets += discarded;
+}
+
+void VideoCodecStatistics::SentFrame()
+{
+  mSentRawFrames++;
+}
+
+void VideoCodecStatistics::Dump()
+{
+  Dump(mEncoderBitRate, "encoder bitrate");
+  Dump(mEncoderFps, "encoder fps");
+  Dump(mDecoderBitRate, "decoder bitrate");
+  Dump(mDecoderFps, "decoder fps");
+}
+
+void VideoCodecStatistics::Dump(RunningStat& s, const char *name)
+{
+  CSFLogDebug(logTag,
+              "%s, mean: %f, variance: %f, standard deviation: %f",
+              name, s.Mean(), s.Variance(), s.StandardDeviation());
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/signaling/src/media-conduit/CodecStatistics.h
@@ -0,0 +1,63 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef CODEC_STATISTICS_H_
+#define CODEC_STATISTICS_H_
+#include <math.h>
+
+#include "nsTArray.h"
+#include "nsISupportsImpl.h"
+#include "webrtc/video_engine/include/vie_codec.h"
+#include "MediaEngineWrapper.h"
+#include "RunningStat.h"
+
+namespace mozilla {
+
+// Statistics-gathering observer for Video Encoder and Decoder
+
+class VideoCodecStatistics : public webrtc::ViEEncoderObserver
+                           , public webrtc::ViEDecoderObserver
+{
+public:
+  VideoCodecStatistics(int channel, webrtc::ViECodec* vieCodec);
+  ~VideoCodecStatistics();
+
+  void SentFrame();
+  virtual void OutgoingRate(const int video_channel,
+    const unsigned int framerate, const unsigned int bitrate) MOZ_OVERRIDE;
+
+  virtual void IncomingCodecChanged(const int video_channel,
+    const webrtc::VideoCodec& video_codec) MOZ_OVERRIDE;
+
+  virtual void IncomingRate(const int video_channel,
+                            const unsigned int framerate,
+                            const unsigned int bitrate) MOZ_OVERRIDE;
+
+  virtual void RequestNewKeyFrame(const int video_channel) MOZ_OVERRIDE {};
+
+  virtual void SuspendChange(int video_channel, bool is_suspended) MOZ_OVERRIDE {};
+  virtual void DecoderTiming(int decode_ms,
+                             int max_decode_ms,
+                             int current_delay_ms,
+                             int target_delay_ms,
+                             int jitter_buffer_ms,
+                             int min_playout_delay_ms,
+                             int render_delay_ms) MOZ_OVERRIDE {}
+  void Dump();
+private:
+  void Dump(RunningStat& s, const char *name);
+
+  int mChannel;
+  uint32_t mSentRawFrames;
+  ScopedCustomReleasePtr<webrtc::ViECodec> mPtrViECodec; // back-pointer
+
+  RunningStat mEncoderBitRate;
+  RunningStat mEncoderFps;
+  uint32_t mEncoderDroppedFrames;
+  RunningStat mDecoderBitRate;
+  RunningStat mDecoderFps;
+  uint32_t mDecoderDiscardedPackets;
+};
+}
+
+#endif //CODEC_STATISTICS_H_
new file mode 100644
--- /dev/null
+++ b/media/webrtc/signaling/src/media-conduit/RunningStat.h
@@ -0,0 +1,66 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+/* Adapted from "Accurately computing running variance - John D. Cook"
+   http://www.johndcook.com/standard_deviation.html */
+
+#ifndef RUNNING_STAT_H_
+#define RUNNING_STAT_H_
+#include <math.h>
+
+namespace mozilla {
+
+class RunningStat
+{
+public:
+  RunningStat() : mN(0) {}
+
+  void Clear()
+  {
+    mN = 0;
+  }
+
+  void Push(double x)
+  {
+    mN++;
+
+    // See Knuth TAOCP vol 2, 3rd edition, page 232
+    if (mN == 1)
+    {
+      mOldM = mNewM = x;
+      mOldS = 0.0;
+    } else {
+      mNewM = mOldM + (x - mOldM) / mN;
+      mNewS = mOldS + (x - mOldM) * (x - mNewM);
+
+      // set up for next iteration
+      mOldM = mNewM;
+      mOldS = mNewS;
+    }
+  }
+
+  int NumDataValues() const
+  {
+    return mN;
+  }
+
+  double Mean() const
+  {
+    return (mN > 0) ? mNewM : 0.0;
+  }
+
+  double Variance() const
+  {
+    return (mN > 1) ? mNewS / (mN - 1) : 0.0;
+  }
+
+  double StandardDeviation() const
+  {
+    return sqrt(Variance());
+  }
+
+private:
+  int mN;
+  double mOldM, mNewM, mOldS, mNewS;
+};
+}
+#endif //RUNNING_STAT_H_
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
@@ -112,16 +112,18 @@ WebrtcVideoConduit::~WebrtcVideoConduit(
   if (mOtherDirection)
   {
     // mOtherDirection owns these now!
     mOtherDirection->mOtherDirection = nullptr;
     // let other side we terminated the channel
     mOtherDirection->mShutDown = true;
     mVideoEngine = nullptr;
   } else {
+    // mVideoCodecStat has a back-ptr to mPtrViECodec that must be released first
+    mVideoCodecStat = nullptr;
     // We can't delete the VideoEngine until all these are released!
     // And we can't use a Scoped ptr, since the order is arbitrary
     mPtrViEBase = nullptr;
     mPtrViECapture = nullptr;
     mPtrViECodec = nullptr;
     mPtrViENetwork = nullptr;
     mPtrViERender = nullptr;
     mPtrRTP = nullptr;
@@ -563,16 +565,19 @@ WebrtcVideoConduit::ConfigureSendMediaCo
     {
       CSFLogError(logTag, "%s Invalid Send Codec", __FUNCTION__);
       return kMediaConduitInvalidSendCodec;
     }
     CSFLogError(logTag, "%s SetSendCodec Failed %d ", __FUNCTION__,
                 mPtrViEBase->LastError());
     return kMediaConduitUnknownError;
   }
+
+  mVideoCodecStat = new VideoCodecStatistics(mChannel, mPtrViECodec);
+
   mSendingWidth = 0;
   mSendingHeight = 0;
 
   if(codecConfig->RtcpFbIsSet(SDP_RTCP_FB_NACK_BASIC)) {
     CSFLogDebug(logTag, "Enabling NACK (send) for video stream\n");
     if (mPtrRTP->SetNACKStatus(mChannel, true) != 0)
     {
       CSFLogError(logTag,  "%s NACKStatus Failed %d ", __FUNCTION__,
@@ -1005,16 +1010,17 @@ WebrtcVideoConduit::SendVideoFrame(unsig
                                    type,
                                    (unsigned long long)capture_time) == -1)
   {
     CSFLogError(logTag,  "%s IncomingFrame Failed %d ", __FUNCTION__,
                                             mPtrViEBase->LastError());
     return kMediaConduitCaptureError;
   }
 
+  mVideoCodecStat->SentFrame();
   CSFLogDebug(logTag, "%s Inserted a frame", __FUNCTION__);
   return kMediaConduitNoError;
 }
 
 // Transport Layer Callbacks
 MediaConduitErrorCode
 WebrtcVideoConduit::ReceivedRTPPacket(const void *data, int len)
 {
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.h
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.h
@@ -5,16 +5,17 @@
 #ifndef VIDEO_SESSION_H_
 #define VIDEO_SESSION_H_
 
 #include "nsAutoPtr.h"
 #include "mozilla/Attributes.h"
 
 #include "MediaConduitInterface.h"
 #include "MediaEngineWrapper.h"
+#include "CodecStatistics.h"
 
 // conflicts with #include of scoped_ptr.h
 #undef FF
 // Video Engine Includes
 #include "webrtc/common_types.h"
 #ifdef FF
 #undef FF // Avoid name collision between scoped_ptr.h and nsCRTGlue.h.
 #endif
@@ -339,13 +340,16 @@ private:
   static const unsigned int sAlphaNum = 7;
   static const unsigned int sAlphaDen = 8;
   static const unsigned int sRoundingPadding = 1024;
 
   mozilla::RefPtr<WebrtcAudioConduit> mSyncedTo;
 
   nsAutoPtr<VideoCodecConfig> mExternalSendCodec;
   nsAutoPtr<VideoCodecConfig> mExternalRecvCodec;
+
+  // statistics object for video codec;
+  nsAutoPtr<VideoCodecStatistics> mVideoCodecStat;
 };
 
 } // end namespace
 
 #endif