diff --git a/dom/media/fmp4/wmf/WMFMediaDataDecoder.cpp b/dom/media/fmp4/wmf/WMFMediaDataDecoder.cpp index 6091e8b85166..32c9785fdca4 100644 --- a/dom/media/fmp4/wmf/WMFMediaDataDecoder.cpp +++ b/dom/media/fmp4/wmf/WMFMediaDataDecoder.cpp @@ -8,6 +8,7 @@ #include "VideoUtils.h" #include "WMFUtils.h" #include "nsTArray.h" +#include "mozilla/Telemetry.h" #include "prlog.h" @@ -44,6 +45,39 @@ WMFMediaDataDecoder::Init() return NS_OK; } +// A single telemetry sample is reported for each MediaDataDecoder object +// that has detected error or produced output successfully. +static void +SendTelemetry(HRESULT hr) +{ + // Collapse the error codes into a range of 0-0xff that can be viewed in + // telemetry histograms. For most MF_E_* errors, unique samples are used, + // retaining the least significant 7 or 8 bits. Other error codes are + // bucketed. + uint32_t sample; + if (SUCCEEDED(hr)) { + sample = 0; + } else if (hr < 0xc00d36b0) { + sample = 1; // low bucket + } else if (hr < 0xc00d3700) { + sample = hr & 0xffU; // MF_E_* + } else if (hr <= 0xc00d3705) { + sample = 0x80 + (hr & 0xfU); // more MF_E_* + } else if (hr < 0xc00d6d60) { + sample = 2; // mid bucket + } else if (hr <= 0xc00d6d78) { + sample = hr & 0xffU; // MF_E_TRANSFORM_* + } else { + sample = 3; // high bucket + } + + nsCOMPtr runnable = NS_NewRunnableFunction( + [sample] { + Telemetry::Accumulate(Telemetry::MEDIA_WMF_DECODE_ERROR, sample); + }); + NS_DispatchToMainThread(runnable); +} + nsresult WMFMediaDataDecoder::Shutdown() { @@ -65,6 +99,9 @@ WMFMediaDataDecoder::ProcessShutdown() if (mMFTManager) { mMFTManager->Shutdown(); mMFTManager = nullptr; + if (!mRecordedError && mHasSuccessfulOutput) { + SendTelemetry(S_OK); + } } mDecoder = nullptr; } @@ -100,6 +137,10 @@ WMFMediaDataDecoder::ProcessDecode(MediaRawData* aSample) if (FAILED(hr)) { NS_WARNING("MFTManager rejected sample"); mCallback->Error(); + if (!mRecordedError) { + SendTelemetry(hr); + mRecordedError = true; + } return; } @@ -115,6 +156,7 @@ WMFMediaDataDecoder::ProcessOutput() HRESULT hr = S_OK; while (SUCCEEDED(hr = mMFTManager->Output(mLastStreamOffset, output)) && output) { + mHasSuccessfulOutput = true; mCallback->Output(output); } if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { @@ -124,6 +166,10 @@ WMFMediaDataDecoder::ProcessOutput() } else if (FAILED(hr)) { NS_WARNING("WMFMediaDataDecoder failed to output data"); mCallback->Error(); + if (!mRecordedError) { + SendTelemetry(hr); + mRecordedError = true; + } } } diff --git a/dom/media/fmp4/wmf/WMFMediaDataDecoder.h b/dom/media/fmp4/wmf/WMFMediaDataDecoder.h index ee16ef4ec9d0..f97c46a7ec1b 100644 --- a/dom/media/fmp4/wmf/WMFMediaDataDecoder.h +++ b/dom/media/fmp4/wmf/WMFMediaDataDecoder.h @@ -109,6 +109,10 @@ private: bool mIsFlushing; bool mIsShutDown; + + // For telemetry + bool mHasSuccessfulOutput = false; + bool mRecordedError = false; }; } // namespace mozilla diff --git a/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp b/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp index 7932f6692407..471989d8c223 100644 --- a/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp +++ b/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp @@ -508,7 +508,7 @@ WMFVideoMFTManager::Output(int64_t aStreamOffset, } // Else unexpected error, assert, and bail. NS_WARNING("WMFVideoMFTManager::Output() unexpected error"); - return E_FAIL; + return hr; } nsRefPtr frame; diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 77d9d16e0cfe..9b3bfdf12274 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -5561,6 +5561,12 @@ "n_buckets": "1000", "description": "The time (in milliseconds) that it took a 'reconfigure thread' request to go round trip." }, + "MEDIA_WMF_DECODE_ERROR": { + "expires_in_version": "50", + "kind": "enumerated", + "n_values": 256, + "description": "WMF media decoder error or success (0) codes." + }, "VIDEO_CANPLAYTYPE_H264_CONSTRAINT_SET_FLAG": { "expires_in_version": "50", "kind": "enumerated",