Bug 1343140 - Output a black frame if Widevine CDM refuses to decode due to losing a key. r=gerald
☠☠ backed out by 62bc57f40c7a ☠ ☠
authorChris Pearce <cpearce@mozilla.com>
Fri, 03 Mar 2017 14:10:28 +1300
changeset 494168 bb2103358f8447a56b59fa84ddb910cf1af6c581
parent 494167 f175c01170723f0f41d4080c01701ac782cdffdf
child 494169 c71f7910dcea9dbd9a16ef463c5983069c90f0b7
child 494178 6c7f1074216eae373792f1ed7929b08be487fa5f
child 494181 f40b7a33ddc5941a8cd5b6fccd3b15a06db7724b
child 494210 62bc57f40c7a78cf8c270e8b21aa3ad883148af0
push id47943
push userdholbert@mozilla.com
push dateMon, 06 Mar 2017 18:52:31 +0000
reviewersgerald
bugs1343140
milestone54.0a1
Bug 1343140 - Output a black frame if Widevine CDM refuses to decode due to losing a key. r=gerald MozReview-Commit-ID: JQon5f87FSF
dom/media/gmp/widevine-adapter/WidevineVideoDecoder.cpp
dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h
dom/media/gmp/widevine-adapter/WidevineVideoFrame.cpp
dom/media/gmp/widevine-adapter/WidevineVideoFrame.h
--- a/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.cpp
+++ b/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.cpp
@@ -73,17 +73,17 @@ WidevineVideoDecoder::InitDecode(const G
   } else if (mCodecType == kGMPVideoCodecVP9) {
     config.codec = VideoDecoderConfig::kCodecVp9;
     config.profile = VideoDecoderConfig::kProfileNotNeeded;
   } else {
     mCallback->Error(GMPInvalidArgErr);
     return;
   }
   config.format = kYv12;
-  config.coded_size = Size(aCodecSettings.mWidth, aCodecSettings.mHeight);
+  config.coded_size = mCodedSize = Size(aCodecSettings.mWidth, aCodecSettings.mHeight);
   nsTArray<uint8_t> extraData;
   if (aCodecSpecificLength > 0) {
     // The first byte is the WebRTC packetization mode, which can be ignored.
     extraData.AppendElements(aCodecSpecific + 1, aCodecSpecificLength - 1);
     config.extra_data = extraData.Elements();
     config.extra_data_size = extraData.Length();
   }
   Status rv = CDM()->InitializeVideoDecoder(config);
@@ -123,17 +123,28 @@ WidevineVideoDecoder::Decode(GMPVideoEnc
   CDM_LOG("WidevineVideoDecoder::Decode(timestamp=%" PRId64 ") rv=%d",
           sample.timestamp, rv);
 
   // Destroy frame, so that the shmem is now free to be used to return
   // output to the Gecko process.
   aInputFrame->Destroy();
   aInputFrame = nullptr;
 
-  if (rv == kSuccess) {
+  if (rv == kSuccess || rv == kNoKey) {
+    if (rv == kNoKey) {
+      CDM_LOG("NoKey for sample at time=%lld!", sample.timestamp);
+      // Somehow our key became unusable. Typically this would happen when
+      // a stream requires output protection, and the configuration changed
+      // such that output protection is no longer available. For example, a
+      // non-compliant monitor was attached. The JS player should notice the
+      // key status changing to "output-restricted", and is supposed to switch
+      // to a stream that doesn't require OP. In order to keep the playback
+      // pipeline rolling, just output a black frame. See bug 1343140.
+      frame.InitToBlack(mCodedSize.width, mCodedSize.height, sample.timestamp);
+    }
     if (!ReturnOutput(frame)) {
       CDM_LOG("WidevineVideoDecoder::Decode() Failed in ReturnOutput()");
       mCallback->Error(GMPDecodeErr);
       return;
     }
     // A reset should only be started at most at level mReturnOutputCallDepth 1,
     // and if it's started it should be finished by that call by the time
     // the it returns, so it should always be false by this point.
--- a/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h
+++ b/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h
@@ -68,13 +68,14 @@ private:
   // Number of calls of ReturnOutput currently in progress.
   int32_t mReturnOutputCallDepth;
   // If we're waiting to drain. Used to prevent drain completing while
   // ReturnOutput calls are still on the stack.
   bool mDrainPending;
   // If a reset is being performed. Used to track if ReturnOutput should
   // dump current frame.
   bool mResetInProgress;
+  cdm::Size mCodedSize;
 };
 
 } // namespace mozilla
 
 #endif // WidevineVideoDecoder_h_
--- a/dom/media/gmp/widevine-adapter/WidevineVideoFrame.cpp
+++ b/dom/media/gmp/widevine-adapter/WidevineVideoFrame.cpp
@@ -119,9 +119,36 @@ WidevineVideoFrame::SetTimestamp(int64_t
 }
 
 int64_t
 WidevineVideoFrame::Timestamp() const
 {
   return mTimestamp;
 }
 
+void
+WidevineVideoFrame::InitToBlack(uint32_t aWidth, uint32_t aHeight, int64_t aTimeStamp)
+{
+  SetFormat(VideoFormat::kI420);
+  SetSize(cdm::Size(aWidth, aHeight));
+  size_t ySize = aWidth * aHeight;
+  size_t uSize = ((aWidth + 1) / 2) * ((aHeight + 1) / 2);
+  WidevineBuffer* buffer = new WidevineBuffer(ySize + uSize);
+  // Black in YCbCr is (0,128,128).
+  memset(buffer->Data(), 0, ySize);
+  memset(buffer->Data() + ySize, 128, uSize);
+  if (mBuffer) {
+    mBuffer->Destroy();
+    mBuffer = nullptr;
+  }
+  SetFrameBuffer(buffer);
+  SetPlaneOffset(VideoFrame::kYPlane, 0);
+  SetStride(VideoFrame::kYPlane, aWidth);
+  // Note: U and V planes are stored at the same place in order to
+  // save memory since their contents are the same.
+  SetPlaneOffset(VideoFrame::kUPlane, ySize);
+  SetStride(VideoFrame::kUPlane, (aWidth + 1) / 2);
+  SetPlaneOffset(VideoFrame::kVPlane, ySize);
+  SetStride(VideoFrame::kVPlane, (aWidth + 1) / 2);
+  SetTimestamp(aTimeStamp);
+}
+
 } // namespace mozilla
--- a/dom/media/gmp/widevine-adapter/WidevineVideoFrame.h
+++ b/dom/media/gmp/widevine-adapter/WidevineVideoFrame.h
@@ -31,16 +31,18 @@ public:
   uint32_t PlaneOffset(cdm::VideoFrame::VideoPlane aPlane) override;
 
   void SetStride(cdm::VideoFrame::VideoPlane aPlane, uint32_t aStride) override;
   uint32_t Stride(cdm::VideoFrame::VideoPlane aPlane) override;
 
   void SetTimestamp(int64_t aTimestamp) override;
   int64_t Timestamp() const override;
 
+  void InitToBlack(uint32_t aWidth, uint32_t aHeight, int64_t aTimeStamp);
+
 protected:
   cdm::VideoFormat mFormat;
   cdm::Size mSize;
   cdm::Buffer* mBuffer;
   uint32_t mPlaneOffsets[kMaxPlanes];
   uint32_t mPlaneStrides[kMaxPlanes];
   int64_t mTimestamp;
 };