diff --git a/dom/media/AdaptiveBufferingPolicy.cpp b/dom/media/AdaptiveBufferingPolicy.cpp new file mode 100644 index 0000000000..2bb48b005c --- /dev/null +++ b/dom/media/AdaptiveBufferingPolicy.cpp @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "AdaptiveBufferingPolicy.h" +#include "mozilla/Logging.h" + +namespace mozilla { + +extern LazyLogModule gMediaDecoderLog; + +#define LOG(arg, ...) MOZ_LOG(gMediaDecoderLog, mozilla::LogLevel::Debug, ("AdaptiveBuffering::%s: " arg, __func__, ##__VA_ARGS__)) + +/** + * Compute estimated memory usage for a single frame. + */ +static uint64_t EstimateFrameMemory(const gfx::IntSize& aSize) +{ + // YUV420 format: 1.5 bytes per pixel + uint64_t width = aSize.width; + uint64_t height = aSize.height; + return (width * height * 3) / 2; +} + +/** + * Calculate resolution tier (affects quality and frame size). + */ +static uint32_t GetResolutionTier(const gfx::IntSize& aSize) +{ + uint32_t pixels = aSize.width * aSize.height; + + // Classify resolution + if (pixels < 480 * 360) return 0; // SD-like + if (pixels < 1280 * 720) return 1; // HD-ready + if (pixels < 1920 * 1080) return 2; // Full HD + if (pixels < 3840 * 2160) return 3; // 4K + return 4; // 8K+ +} + +AdaptiveBufferingPolicy::Config +AdaptiveBufferingPolicy::ComputeOptimalConfig( + const gfx::IntSize& aVideoSize, + uint32_t aFrameRate, + uint64_t aVideoBitrate, + bool aHardwareAccelerated, + uint64_t aAvailableMemory) +{ + Config config; + uint32_t resolutionTier = GetResolutionTier(aVideoSize); + uint64_t frameMemory = EstimateFrameMemory(aVideoSize); + + // Adjust video queue size based on resolution and memory availability + uint32_t recommendedQueueSize = config.mDefaultVideoQueueFrames; + + if (aHardwareAccelerated) { + recommendedQueueSize = config.mHWAccelVideoQueueFrames; + } + + // For high-resolution content, reduce queue size to save memory + if (resolutionTier >= 3) { // 4K or higher + recommendedQueueSize = std::max(config.mMinVideoQueueFrames, + recommendedQueueSize / 2); + config.mMaxVideoBufferMemory = 50 * 1024 * 1024; // 50MB for 4K + } else if (resolutionTier == 2) { // Full HD + config.mMaxVideoBufferMemory = 75 * 1024 * 1024; // 75MB + } + + // Constrain by available memory + uint64_t maxFramesInMemory = config.mMaxVideoBufferMemory / + std::max(frameMemory, (uint64_t)1); + recommendedQueueSize = std::min((uint32_t)maxFramesInMemory, recommendedQueueSize); + recommendedQueueSize = std::max(config.mMinVideoQueueFrames, recommendedQueueSize); + + config.mDefaultVideoQueueFrames = recommendedQueueSize; + + // Adjust decode speed threshold based on bitrate + if (aVideoBitrate > 0) { + // High bitrate content may need faster decode speed + if (aVideoBitrate > 10000000) { // >10 Mbps + config.mDecodeSpeedRatio = 2.0; + } else if (aVideoBitrate > 5000000) { // >5 Mbps + config.mDecodeSpeedRatio = 1.75; + } + } + + // For network streams, use more conservative buffering + if (aVideoBitrate > 0) { + config.mLowAudioThreshold = 500000; // 500ms + config.mAmpleAudioThreshold = 3000000; // 3s + } + + LOG("Computed config: queueSize=%u, maxMemory=%llu, decodeRatio=%.2f (res=%u)", + recommendedQueueSize, + config.mMaxVideoBufferMemory, + config.mDecodeSpeedRatio, + resolutionTier); + + return config; +} + +uint32_t AdaptiveBufferingPolicy::GetOptimalVideoQueueSize( + const gfx::IntSize& aVideoSize, + bool aHardwareAccelerated, + uint64_t aAvailableMemory) +{ + // Start with base size + uint32_t queueSize = aHardwareAccelerated ? 5 : 10; + + uint64_t frameMemory = EstimateFrameMemory(aVideoSize); + uint64_t maxFramesInMemory = (100 * 1024 * 1024) / frameMemory; + + // Constrain by available memory + queueSize = std::min((uint32_t)maxFramesInMemory, queueSize); + + return std::max(3u, queueSize); +} + +uint64_t AdaptiveBufferingPolicy::GetOptimalAudioThreshold(bool aIsNetworkStream) +{ + if (aIsNetworkStream) { + return 500000; // 500ms for network (more conservative) + } + return 300000; // 300ms for local files +} + +bool AdaptiveBufferingPolicy::ShouldSkipFrame( + int64_t aAudioTimeUs, + int64_t aFrameDisplayTimeUs, + int64_t aVideoDecodeTimeUs, + uint32_t aThresholdMs) +{ + // Skip if frame is already in the past relative to audio + int64_t thresholdUs = aThresholdMs * 1000; + + // Calculate how late this frame is + int64_t timeLatenessUs = aAudioTimeUs - aFrameDisplayTimeUs; + + // Skip if frame is significantly behind audio timeline + if (timeLatenessUs > thresholdUs) { + return true; + } + + // Also skip if decoding this frame would take us further behind + int64_t projectedLatenessUs = timeLatenessUs + aVideoDecodeTimeUs; + if (projectedLatenessUs > (thresholdUs * 2)) { + return true; + } + + return false; +} + +} // namespace mozilla diff --git a/dom/media/AdaptiveBufferingPolicy.h b/dom/media/AdaptiveBufferingPolicy.h new file mode 100644 index 0000000000..2f75157ff9 --- /dev/null +++ b/dom/media/AdaptiveBufferingPolicy.h @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 MOZILLA_ADAPTIVEBUFFERINGPOLICY_H_ +#define MOZILLA_ADAPTIVEBUFFERINGPOLICY_H_ + +#include "mozilla/Atomics.h" +#include "TimeUnits.h" +#include "gfxTypes.h" + +namespace mozilla { + +/** + * Adaptive buffering policy manager for video playback. + * + * Dynamically adjusts buffering thresholds based on: + * - Available system memory + * - Video resolution and bitrate + * - Decode speed vs real-time ratio + * - Network conditions (if applicable) + * + * This reduces memory usage while maintaining smooth playback. + */ +class AdaptiveBufferingPolicy { +public: + struct Config { + // Audio buffering thresholds (microseconds) + uint64_t mLowAudioThreshold = 300000; // 300ms - trigger faster decoding + uint64_t mAmpleAudioThreshold = 2000000; // 2s - target comfortable level + + // Video frame queue sizing + uint32_t mMinVideoQueueFrames = 3; // Absolute minimum + uint32_t mDefaultVideoQueueFrames = 10; // Default for standard content + uint32_t mMaxVideoQueueFrames = 20; // Absolute maximum + + // Hardware acceleration thresholds + uint32_t mHWAccelVideoQueueFrames = 5; // Target for HW-accelerated playback + + // Memory limits (bytes) + uint64_t mMaxVideoBufferMemory = 100 * 1024 * 1024; // 100MB default + uint64_t mTargetVideoBufferMemory = 50 * 1024 * 1024; // 50MB target + + // Decode speed thresholds + double mDecodeSpeedRatio = 1.5; // Must decode 1.5x realtime speed + + // Frame skip configuration + bool mEnableAdaptiveFrameSkip = true; + bool mSkipNonKeyframes = true; + uint32_t mFrameSkipThresholdMs = 60; // Skip if >60ms behind audio + }; + + /** + * Adjust buffering policy based on system state and video properties. + * Returns optimized configuration for the given video specifications. + */ + static Config ComputeOptimalConfig( + const gfx::IntSize& aVideoSize, + uint32_t aFrameRate, + uint64_t aVideoBitrate, + bool aHardwareAccelerated, + uint64_t aAvailableMemory); + + /** + * Get the recommended video queue size based on context. + */ + static uint32_t GetOptimalVideoQueueSize( + const gfx::IntSize& aVideoSize, + bool aHardwareAccelerated, + uint64_t aAvailableMemory); + + /** + * Get audio buffering threshold based on network conditions. + */ + static uint64_t GetOptimalAudioThreshold(bool aIsNetworkStream); + + /** + * For HD+ content with limited memory, suggest lower priority video frames + * that can be safely skipped without visible quality loss. + */ + static bool ShouldSkipFrame( + int64_t aAudioTimeUs, + int64_t aFrameDisplayTimeUs, + int64_t aVideoDecodeTimeUs, + uint32_t aThresholdMs); +}; + +} // namespace mozilla + +#endif // MOZILLA_ADAPTIVEBUFFERINGPOLICY_H_ diff --git a/dom/media/FramePool.cpp b/dom/media/FramePool.cpp new file mode 100644 index 0000000000..08e0fc39d6 --- /dev/null +++ b/dom/media/FramePool.cpp @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "FramePool.h" +#include "mozilla/Logging.h" +#include "ImageContainer.h" + +namespace mozilla { + +extern LazyLogModule gMediaDecoderLog; + +#undef LOG +#define LOG(arg, ...) MOZ_LOG(gMediaDecoderLog, mozilla::LogLevel::Debug, ("FramePool::%s: " arg, __func__, ##__VA_ARGS__)) +#define LOGV(arg, ...) MOZ_LOG(gMediaDecoderLog, mozilla::LogLevel::Verbose, ("FramePool::%s: " arg, __func__, ##__VA_ARGS__)) + +FramePool::FramePool(size_t aMaxFrames) + : mMutex("FramePool::mMutex") + , mMaxPoolSize(aMaxFrames > 0 ? aMaxFrames : 16) +{ + LOG("FramePool created with max size: %zu", mMaxPoolSize); +} + +FramePool::~FramePool() +{ + Clear(); +} + +RefPtr FramePool::AcquireFrame(const gfx::IntSize& aSize) +{ + MutexAutoLock lock(mMutex); + + // Try to reuse a frame from pool + if (!mFramePool.IsEmpty()) { + RefPtr frame = mFramePool[mFramePool.Length() - 1]; + mFramePool.RemoveElementAt(mFramePool.Length() - 1); + mFramesReused++; + LOGV("Reused frame from pool, pool size now: %zu", mFramePool.Length()); + return frame; + } + + // No pooled frame available; we cannot reliably construct a specific + // Image subclass here (requires platform-specific recycle bin). Return + // nullptr and let the caller allocate an appropriate Image if needed. + mTotalAllocated++; + LOG("No pooled frame available, returning nullptr (alloc attempts: %zu)", mTotalAllocated); + return nullptr; +} + +void FramePool::ReleaseFrame(layers::Image* aFrame) +{ + if (!aFrame) { + return; + } + + MutexAutoLock lock(mMutex); + + // Only pool frame if we haven't reached max capacity + if (mFramePool.Length() < mMaxPoolSize) { + mFramePool.AppendElement(RefPtr(aFrame)); + + // Track peak pool size + if (mFramePool.Length() > mPeakPoolSize) { + mPeakPoolSize = mFramePool.Length(); + } + + LOGV("Released frame to pool, pool size: %zu/%zu", + mFramePool.Length(), mMaxPoolSize); + } else { + // Frame exceeds pool capacity, let it be released + LOGV("Frame pool at capacity, releasing frame"); + } +} + +void FramePool::Clear() +{ + MutexAutoLock lock(mMutex); + mFramePool.Clear(); + LOG("Frame pool cleared"); +} + +size_t FramePool::PoolSize() const +{ + MutexAutoLock lock(mMutex); + return mFramePool.Length(); +} + +size_t FramePool::TotalFrames() const +{ + MutexAutoLock lock(mMutex); + return mTotalAllocated; +} + +} // namespace mozilla diff --git a/dom/media/FramePool.h b/dom/media/FramePool.h new file mode 100644 index 0000000000..836edd7543 --- /dev/null +++ b/dom/media/FramePool.h @@ -0,0 +1,104 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 MOZILLA_FRAMEPOOL_H_ +#define MOZILLA_FRAMEPOOL_H_ + +#include "mozilla/Atomics.h" +#include "mozilla/Mutex.h" +#include "mozilla/RefPtr.h" +#include "nsTArray.h" +#include "gfxTypes.h" + +namespace mozilla { + +namespace layers { +class Image; +} // namespace layers + +/** + * FramePool manages a pool of reusable video frame buffers to reduce + * memory allocation/deallocation overhead during playback. + * + * Usage: + * RefPtr pool = new FramePool(max_frames); + * RefPtr frame = pool->AcquireFrame(size); + * // use frame... + * pool->ReleaseFrame(frame); // returns to pool or deallocates + */ +class FramePool { +public: + explicit FramePool(size_t aMaxFrames = 16); + private: + ~FramePool(); + + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FramePool) + + /** + * Acquire a frame buffer from the pool. If no pooled frames are available, + * allocates a new one. Thread-safe. + */ + RefPtr AcquireFrame(const gfx::IntSize& aSize); + + /** + * Return a frame to the pool for reuse. If pool is full, frame is released. + * Thread-safe. + */ + void ReleaseFrame(layers::Image* aFrame); + + /** + * Clear all pooled frames and release memory. + */ + void Clear(); + + /** + * Get current number of frames in pool. + */ + size_t PoolSize() const; + + /** + * Get total frames allocated (pooled + in use). + */ + size_t TotalFrames() const; + + /** + * Get statistics about pool usage. + */ + struct Stats { + size_t mPooledFrames; // Frames available in pool + size_t mAllocatedFrames; // Total frames ever allocated + size_t mReusedFrames; // Frames reused from pool + size_t mPeakPoolSize; // Maximum simultaneous frames in pool + }; + + Stats GetStats() const { + MutexAutoLock lock(mMutex); + return {mFramePool.Length(), mTotalAllocated, mFramesReused, mPeakPoolSize}; + } + + /** + * Reset statistics counters. + */ + void ResetStats() { + MutexAutoLock lock(mMutex); + mFramesReused = 0; + mTotalAllocated = 0; + mPeakPoolSize = 0; + } + +private: + mutable Mutex mMutex; + nsTArray> mFramePool; + const size_t mMaxPoolSize; + + // Statistics + size_t mTotalAllocated = 0; + size_t mFramesReused = 0; + size_t mPeakPoolSize = 0; +}; + +} // namespace mozilla + +#endif // MOZILLA_FRAMEPOOL_H_ diff --git a/dom/media/VideoPlaybackStats.cpp b/dom/media/VideoPlaybackStats.cpp new file mode 100644 index 0000000000..ab5c23880b --- /dev/null +++ b/dom/media/VideoPlaybackStats.cpp @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "VideoPlaybackStats.h" +#include "mozilla/Logging.h" +#include "nsPrintfCString.h" + +namespace mozilla { + +extern LazyLogModule gMediaDecoderLog; + +#define LOG(arg, ...) MOZ_LOG(gMediaDecoderLog, mozilla::LogLevel::Debug, ("VideoPlaybackStats::%s: " arg, __func__, ##__VA_ARGS__)) + +VideoPlaybackStats::VideoPlaybackStats() + : mMutex("VideoPlaybackStats::mMutex") +{ + LOG("VideoPlaybackStats created"); +} + +VideoPlaybackStats::~VideoPlaybackStats() +{ + LOG("VideoPlaybackStats destroyed - Total frames decoded: %llu, displayed: %llu, skipped: %llu", + mStats.mTotalFramesDecoded, + mStats.mTotalFramesDisplayed, + mStats.mTotalFramesSkipped); +} + +void VideoPlaybackStats::RecordFrameDecoded(const FrameStats& aStats) +{ + MutexAutoLock lock(mMutex); + + mStats.mTotalFramesDecoded++; + + if (aStats.mDecodeTimeUs > 0) { + mTotalDecodeTimeUs += aStats.mDecodeTimeUs; + mSampleCount++; + + // Update average decode time + mStats.mAverageDecodeTimeMs = (double)mTotalDecodeTimeUs / + (mSampleCount * 1000.0); + + // Track max decode time + double decodeTimeMs = aStats.mDecodeTimeUs / 1000.0; + if (decodeTimeMs > mStats.mMaxDecodeTimeMs) { + mStats.mMaxDecodeTimeMs = decodeTimeMs; + } + } + + if (aStats.mMemoryBytes > 0) { + if (aStats.mMemoryBytes > mStats.mPeakMemoryUsage) { + mStats.mPeakMemoryUsage = aStats.mMemoryBytes; + } + } +} + +void VideoPlaybackStats::RecordFrameDisplayed(int64_t aDisplayTimeUs, uint32_t aQueueSize) +{ + MutexAutoLock lock(mMutex); + + mStats.mTotalFramesDisplayed++; + + // Track queue statistics + if (aQueueSize > mStats.mPeakQueueSize) { + mStats.mPeakQueueSize = aQueueSize; + } + + // Update rolling average queue size + uint64_t total = mStats.mAverageQueueSize * mStats.mTotalFramesDisplayed; + mStats.mAverageQueueSize = (total + aQueueSize) / (mStats.mTotalFramesDisplayed + 1); +} + +void VideoPlaybackStats::RecordFrameSkipped(bool aIsKeyframe) +{ + MutexAutoLock lock(mMutex); + mStats.mTotalFramesSkipped++; +} + +void VideoPlaybackStats::RecordFrameDropped() +{ + MutexAutoLock lock(mMutex); + mStats.mTotalFramesDropped++; +} + +void VideoPlaybackStats::RecordMemoryUsage(uint64_t aBytesUsed) +{ + MutexAutoLock lock(mMutex); + + if (aBytesUsed > mStats.mPeakMemoryUsage) { + mStats.mPeakMemoryUsage = aBytesUsed; + } + + mMemoryAccumulator += aBytesUsed; + mTotalMemoryMeasurements++; + + if (mTotalMemoryMeasurements > 0) { + mStats.mAverageMemoryUsage = mMemoryAccumulator / mTotalMemoryMeasurements; + } +} + +VideoPlaybackStats::PlaybackStats VideoPlaybackStats::GetStats() const +{ + MutexAutoLock lock(mMutex); + return mStats; +} + +void VideoPlaybackStats::Reset() +{ + MutexAutoLock lock(mMutex); + mStats = PlaybackStats(); + mSampleCount = 0; + mTotalDecodeTimeUs = 0; + mTotalMemoryMeasurements = 0; + mMemoryAccumulator = 0; + LOG("Statistics reset"); +} + +void VideoPlaybackStats::GetDebugInfo(nsAString& aOutput) const +{ + MutexAutoLock lock(mMutex); + + nsPrintfCString info( + "Video Playback Statistics:\n" + " Frames decoded: %llu\n" + " Frames displayed: %llu\n" + " Frames skipped: %llu\n" + " Frames dropped: %llu\n" + " Average decode time: %.2f ms\n" + " Max decode time: %.2f ms\n" + " Peak memory usage: %llu MB\n" + " Average memory usage: %llu MB\n" + " Average queue size: %u frames\n" + " Peak queue size: %u frames\n" + " Hardware accelerated: %s\n", + mStats.mTotalFramesDecoded, + mStats.mTotalFramesDisplayed, + mStats.mTotalFramesSkipped, + mStats.mTotalFramesDropped, + mStats.mAverageDecodeTimeMs, + mStats.mMaxDecodeTimeMs, + mStats.mPeakMemoryUsage / (1024 * 1024), + mStats.mAverageMemoryUsage / (1024 * 1024), + mStats.mAverageQueueSize, + mStats.mPeakQueueSize, + mStats.mIsHardwareAccelerated ? "yes" : "no"); + + aOutput.AssignASCII(info.get()); +} + +} // namespace mozilla diff --git a/dom/media/VideoPlaybackStats.h b/dom/media/VideoPlaybackStats.h new file mode 100644 index 0000000000..3b5b48e890 --- /dev/null +++ b/dom/media/VideoPlaybackStats.h @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 MOZILLA_VIDEOPLAYBACKSTATS_H_ +#define MOZILLA_VIDEOPLAYBACKSTATS_H_ + +#include "mozilla/Atomics.h" +#include "mozilla/Mutex.h" +#include "mozilla/TimeStamp.h" +#include "TimeUnits.h" + +class nsAString; + +namespace mozilla { + +/** + * Tracks performance and memory statistics for video playback. + * Useful for debugging performance issues and optimizing buffering policies. + */ +class VideoPlaybackStats { +public: + struct FrameStats { + // Timing information + TimeStamp mDecodeStart; + TimeStamp mDecodeEnd; + int64_t mDecodeTimeUs = 0; + int64_t mDisplayTimeUs = 0; + + // Frame properties + bool mIsKeyframe = false; + bool mWasSkipped = false; + uint32_t mWidth = 0; + uint32_t mHeight = 0; + uint64_t mMemoryBytes = 0; + }; + + struct PlaybackStats { + // Frame statistics + uint64_t mTotalFramesDecoded = 0; + uint64_t mTotalFramesDisplayed = 0; + uint64_t mTotalFramesSkipped = 0; + uint64_t mTotalFramesDropped = 0; + + // Memory statistics (peak values) + uint64_t mPeakMemoryUsage = 0; + uint64_t mAverageMemoryUsage = 0; + uint64_t mTotalMemoryAllocated = 0; + + // Performance metrics + double mAverageDecodeTimeMs = 0.0; + double mMaxDecodeTimeMs = 0.0; + int32_t mFramesLateByMs = 0; + + // Buffer statistics + uint32_t mAverageQueueSize = 0; + uint32_t mPeakQueueSize = 0; + + // Hardware acceleration info + bool mIsHardwareAccelerated = false; + uint32_t mHardwareSkipCount = 0; + }; + + VideoPlaybackStats(); + + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoPlaybackStats) + + /** + * Record a decoded frame and its timing information. + */ + void RecordFrameDecoded(const FrameStats& aStats); + + /** + * Record a displayed frame. + */ + void RecordFrameDisplayed(int64_t aDisplayTimeUs, uint32_t aQueueSize); + + /** + * Record a skipped frame. + */ + void RecordFrameSkipped(bool aIsKeyframe); + + /** + * Record a dropped frame. + */ + void RecordFrameDropped(); + + /** + * Record memory usage snapshot. + */ + void RecordMemoryUsage(uint64_t aBytesUsed); + + /** + * Set hardware acceleration status. + */ + void SetHardwareAccelerated(bool aIsHWAccel) { + mStats.mIsHardwareAccelerated = aIsHWAccel; + } + + /** + * Get current statistics snapshot. + */ + PlaybackStats GetStats() const; + + /** + * Reset all statistics (start fresh measurement). + */ + void Reset(); + + /** + * Get human-readable statistics summary for debugging. + */ + void GetDebugInfo(nsAString& aOutput) const; + +private: + ~VideoPlaybackStats(); + mutable Mutex mMutex; + PlaybackStats mStats; + + uint64_t mSampleCount = 0; // For computing averages + uint64_t mTotalDecodeTimeUs = 0; + uint64_t mTotalMemoryMeasurements = 0; + uint64_t mMemoryAccumulator = 0; +}; + +} // namespace mozilla + +#endif // MOZILLA_VIDEOPLAYBACKSTATS_H_ diff --git a/dom/media/moz.build b/dom/media/moz.build index ca3cdac1ca..939755a483 100644 --- a/dom/media/moz.build +++ b/dom/media/moz.build @@ -94,6 +94,7 @@ EXPORTS += [ 'DOMMediaStream.h', 'EncodedBufferCache.h', 'FileBlockCache.h', + 'FramePool.h', 'FrameStatistics.h', 'Intervals.h', 'Latency.h', @@ -140,6 +141,7 @@ EXPORTS += [ 'TrackUnionStream.h', 'VideoFrameContainer.h', 'VideoLimits.h', + 'VideoPlaybackStats.h', 'VideoSegment.h', 'VideoUtils.h', 'VorbisUtils.h', @@ -186,6 +188,7 @@ EXPORTS.mozilla.dom += [ UNIFIED_SOURCES += [ 'AccurateSeekTask.cpp', + 'AdaptiveBufferingPolicy.cpp', 'ADTSDecoder.cpp', 'ADTSDemuxer.cpp', 'AudioCaptureStream.cpp', @@ -204,6 +207,7 @@ UNIFIED_SOURCES += [ 'DOMMediaStream.cpp', 'EncodedBufferCache.cpp', 'FileBlockCache.cpp', + 'FramePool.cpp', 'GetUserMediaRequest.cpp', 'GraphDriver.cpp', 'Latency.cpp', @@ -244,6 +248,7 @@ UNIFIED_SOURCES += [ 'TrackUnionStream.cpp', 'VideoFrameContainer.cpp', 'VideoPlaybackQuality.cpp', + 'VideoPlaybackStats.cpp', 'VideoSegment.cpp', 'VideoStreamTrack.cpp', 'VideoTrack.cpp',