Bug 994557 - part2: 1. fix bug in finishCluster function. 2. Can flush metadata only. 3. Ensure the keyframe is placed at the beginning of cluster. r=rillian
authorBenjamin Chen <bechen@mozilla.com>
Wed, 23 Apr 2014 12:04:27 +0800
changeset 198237 80dba24cc92979858f88cffdccde906a3b6d8308
parent 198236 0930742ce5c6e9c2ee97ef7e8037cbd7c7c853c0
child 198238 368a6f1f7eea8b7a99a2f89b32649aec499291ac
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrillian
bugs994557
milestone31.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 994557 - part2: 1. fix bug in finishCluster function. 2. Can flush metadata only. 3. Ensure the keyframe is placed at the beginning of cluster. r=rillian
content/media/webm/EbmlComposer.cpp
content/media/webm/EbmlComposer.h
--- a/content/media/webm/EbmlComposer.cpp
+++ b/content/media/webm/EbmlComposer.cpp
@@ -55,63 +55,83 @@ void EbmlComposer::GenerateHeader()
         Ebml_EndSubElement(&ebml, &trackLoc);
       }
     }
     // The Recording length is unknown and
     // ignore write the whole Segment element size
   }
   MOZ_ASSERT(ebml.offset <= DEFAULT_HEADER_SIZE + mCodecPrivateData.Length(),
              "write more data > EBML_BUFFER_SIZE");
-  mClusterBuffs.AppendElement();
-  mClusterBuffs.LastElement().SetLength(ebml.offset);
-  memcpy(mClusterBuffs.LastElement().Elements(), ebml.buf, ebml.offset);
+  auto block = mClusterBuffs.AppendElement();
+  block->SetLength(ebml.offset);
+  memcpy(block->Elements(), ebml.buf, ebml.offset);
+  mFlushState |= FLUSH_METADATA;
+}
+
+void EbmlComposer::FinishMetadata()
+{
+  if (mFlushState & FLUSH_METADATA) {
+    // We don't remove the first element of mClusterBuffs because the
+    // |mClusterHeaderIndex| may have value.
+    mClusterCanFlushBuffs.AppendElement()->SwapElements(mClusterBuffs[0]);
+    mFlushState &= ~FLUSH_METADATA;
+  }
 }
 
 void EbmlComposer::FinishCluster()
 {
-  MOZ_ASSERT(mClusterLengthLoc > 0 );
-  MOZ_ASSERT(mClusterHeaderIndex > 0);
-  for (uint32_t i = 0; i < mClusterBuffs.Length(); i++) {
-    mClusterCanFlushBuffs.AppendElement()->SwapElements(mClusterBuffs[i]);
+  FinishMetadata();
+  if (!(mFlushState & FLUSH_CLUSTER)) {
+    // No completed cluster available.
+    return;
   }
-  mClusterBuffs.Clear();
+
+  MOZ_ASSERT(mClusterLengthLoc > 0);
   EbmlGlobal ebml;
   EbmlLoc ebmlLoc;
   ebmlLoc.offset = mClusterLengthLoc;
-  ebml.offset = mClusterCanFlushBuffs[mClusterHeaderIndex].Length();
-  ebml.buf = mClusterCanFlushBuffs[mClusterHeaderIndex].Elements();
+  ebml.offset = mClusterBuffs[mClusterHeaderIndex].Length();
+  ebml.buf = mClusterBuffs[mClusterHeaderIndex].Elements();
   Ebml_EndSubElement(&ebml, &ebmlLoc);
+  // Move the mClusterBuffs data from mClusterHeaderIndex that we can skip
+  // the metadata and the rest P-frames after ContainerWriter::FLUSH_NEEDED.
+  for (uint32_t i = mClusterHeaderIndex; i < mClusterBuffs.Length(); i++) {
+    mClusterCanFlushBuffs.AppendElement()->SwapElements(mClusterBuffs[i]);
+  }
+
   mClusterHeaderIndex = 0;
   mClusterLengthLoc = 0;
+  mClusterBuffs.Clear();
+  mFlushState &= ~FLUSH_CLUSTER;
 }
 
 void
 EbmlComposer::WriteSimpleBlock(EncodedFrame* aFrame)
 {
   EbmlGlobal ebml;
   ebml.offset = 0;
 
-  if (aFrame->GetFrameType() == EncodedFrame::FrameType::VP8_I_FRAME && mClusterHeaderIndex > 0) {
+  if (aFrame->GetFrameType() == EncodedFrame::FrameType::VP8_I_FRAME) {
     FinishCluster();
   }
 
-  mClusterBuffs.AppendElement();
-  mClusterBuffs.LastElement().SetLength(aFrame->GetFrameData().Length() + DEFAULT_HEADER_SIZE);
-  ebml.buf = mClusterBuffs.LastElement().Elements();
+  auto block = mClusterBuffs.AppendElement();
+  block->SetLength(aFrame->GetFrameData().Length() + DEFAULT_HEADER_SIZE);
+  ebml.buf = block->Elements();
 
   if (aFrame->GetFrameType() == EncodedFrame::FrameType::VP8_I_FRAME) {
     EbmlLoc ebmlLoc;
     Ebml_StartSubElement(&ebml, &ebmlLoc, Cluster);
+    MOZ_ASSERT(mClusterBuffs.Length() > 0);
     // current cluster header array index
     mClusterHeaderIndex = mClusterBuffs.Length() - 1;
     mClusterLengthLoc = ebmlLoc.offset;
-    if (aFrame->GetFrameType() != EncodedFrame::FrameType::VORBIS_AUDIO_FRAME) {
-      mClusterTimecode = aFrame->GetTimeStamp() / PR_USEC_PER_MSEC;
-    }
+    mClusterTimecode = aFrame->GetTimeStamp() / PR_USEC_PER_MSEC;
     Ebml_SerializeUnsigned(&ebml, Timecode, mClusterTimecode);
+    mFlushState |= FLUSH_CLUSTER;
   }
 
   if (aFrame->GetFrameType() != EncodedFrame::FrameType::VORBIS_AUDIO_FRAME) {
     short timeCode = aFrame->GetTimeStamp() / PR_USEC_PER_MSEC
                      - mClusterTimecode;
     writeSimpleBlock(&ebml, 0x1, timeCode, aFrame->GetFrameType() ==
                      EncodedFrame::FrameType::VP8_I_FRAME,
                      0, 0, (unsigned char*)aFrame->GetFrameData().Elements(),
@@ -119,17 +139,17 @@ EbmlComposer::WriteSimpleBlock(EncodedFr
   } else {
     writeSimpleBlock(&ebml, 0x2, 0, false,
                      0, 0, (unsigned char*)aFrame->GetFrameData().Elements(),
                      aFrame->GetFrameData().Length());
   }
   MOZ_ASSERT(ebml.offset <= DEFAULT_HEADER_SIZE +
              aFrame->GetFrameData().Length(),
              "write more data > EBML_BUFFER_SIZE");
-  mClusterBuffs.LastElement().SetLength(ebml.offset);
+  block->SetLength(ebml.offset);
 }
 
 void
 EbmlComposer::SetVideoConfig(uint32_t aWidth, uint32_t aHeight,
                              uint32_t aDisplayWidth, uint32_t aDisplayHeight,
                              float aFrameRate)
 {
   MOZ_ASSERT(aWidth > 0, "Width should > 0");
@@ -155,28 +175,35 @@ EbmlComposer::SetAudioConfig(uint32_t aS
   mBitDepth = aBitDepth;
   mChannels = aChannels;
 }
 
 void
 EbmlComposer::ExtractBuffer(nsTArray<nsTArray<uint8_t> >* aDestBufs,
                             uint32_t aFlag)
 {
-  if ((aFlag & ContainerWriter::FLUSH_NEEDED) && mClusterHeaderIndex > 0) {
+  if ((aFlag & ContainerWriter::FLUSH_NEEDED) ||
+      (aFlag & ContainerWriter::GET_HEADER))
+  {
+    FinishMetadata();
+  }
+  if (aFlag & ContainerWriter::FLUSH_NEEDED)
+  {
     FinishCluster();
   }
   // aDestBufs may have some element
   for (uint32_t i = 0; i < mClusterCanFlushBuffs.Length(); i++) {
     aDestBufs->AppendElement()->SwapElements(mClusterCanFlushBuffs[i]);
   }
   mClusterCanFlushBuffs.Clear();
 }
 
 EbmlComposer::EbmlComposer()
-  : mClusterHeaderIndex(0)
+  : mFlushState(FLUSH_NONE)
+  , mClusterHeaderIndex(0)
   , mClusterLengthLoc(0)
   , mClusterTimecode(0)
   , mWidth(0)
   , mHeight(0)
   , mFrameRate(0)
   , mSampleFreq(0)
   , mBitDepth(0)
   , mChannels(0)
--- a/content/media/webm/EbmlComposer.h
+++ b/content/media/webm/EbmlComposer.h
@@ -41,23 +41,33 @@ public:
    */
   void WriteSimpleBlock(EncodedFrame* aFrame);
   /*
    * Get valid cluster data.
    */
   void ExtractBuffer(nsTArray<nsTArray<uint8_t> >* aDestBufs,
                      uint32_t aFlag = 0);
 private:
+  // Move the metadata data to mClusterCanFlushBuffs.
+  void FinishMetadata();
   // Close current cluster and move data to mClusterCanFlushBuffs.
   void FinishCluster();
   // The temporary storage for cluster data.
   nsTArray<nsTArray<uint8_t> > mClusterBuffs;
   // The storage which contain valid cluster data.
   nsTArray<nsTArray<uint8_t> > mClusterCanFlushBuffs;
-  // Indicate the header index in mClusterBuffs.
+
+  // Indicate the data types in mClusterBuffs.
+  enum {
+    FLUSH_NONE = 0,
+    FLUSH_METADATA = 1 << 0,
+    FLUSH_CLUSTER = 1 << 1
+  };
+  uint32_t mFlushState;
+  // Indicate the cluster header index in mClusterBuffs.
   uint32_t mClusterHeaderIndex;
   // The cluster length position.
   uint64_t mClusterLengthLoc;
   // Audio codec specific header data.
   nsTArray<uint8_t> mCodecPrivateData;
 
   // The timecode of the cluster.
   uint64_t mClusterTimecode;