Bug 1182100 - Add MP3 demuxer tests for stream resources with unknown lengths. r=kinetik
authorEugen Sawin <esawin@mozilla.com>
Thu, 09 Jul 2015 22:42:23 +0200
changeset 273263 31fef8afde5a9cc5d96e72318a320e1b52e9ead8
parent 273262 a9e266811633fa2b0e589fd6f09c560e98b99f54
child 273264 04a66937c275dc5a01aaad56835cfe2922dd178f
push idunknown
push userunknown
push dateunknown
reviewerskinetik
bugs1182100
milestone42.0a1
Bug 1182100 - Add MP3 demuxer tests for stream resources with unknown lengths. r=kinetik
dom/media/gtest/MockMediaResource.h
dom/media/gtest/TestMP3Demuxer.cpp
--- a/dom/media/gtest/MockMediaResource.h
+++ b/dom/media/gtest/MockMediaResource.h
@@ -72,18 +72,20 @@ public:
   virtual const nsCString& GetContentType() const override
   {
     return mContentType;
   }
 
   void MockClearBufferedRanges();
   void MockAddBufferedRange(int64_t aStart, int64_t aEnd);
 
+protected:
+  virtual ~MockMediaResource();
+
 private:
-  virtual ~MockMediaResource();
   FILE* mFileHandle;
   const char* mFileName;
   nsTArray<MediaByteRange> mRanges;
   Atomic<int> mEntry;
   nsCString mContentType;
 };
 }
 
--- a/dom/media/gtest/TestMP3Demuxer.cpp
+++ b/dom/media/gtest/TestMP3Demuxer.cpp
@@ -7,20 +7,44 @@
 #include <vector>
 
 #include "MP3Demuxer.h"
 #include "mozilla/ArrayUtils.h"
 #include "MockMediaResource.h"
 
 using namespace mp3;
 
+// Regular MP3 file mock resource.
+class MockMP3MediaResource : public MockMediaResource {
+public:
+  explicit MockMP3MediaResource(const char* aFileName)
+    : MockMediaResource(aFileName)
+  {}
+
+protected:
+  virtual ~MockMP3MediaResource() {}
+};
+
+// MP3 stream mock resource.
+class MockMP3StreamMediaResource : public MockMP3MediaResource {
+public:
+  explicit MockMP3StreamMediaResource(const char* aFileName)
+    : MockMP3MediaResource(aFileName)
+  {}
+
+  int64_t GetLength() override { return -1; }
+
+protected:
+  virtual ~MockMP3StreamMediaResource() {}
+};
+
 struct MP3Resource {
   const char* mFilePath;
   bool mIsVBR;
-  uint64_t mFileSize;
+  int64_t mFileSize;
   int32_t mMPEGLayer;
   int32_t mMPEGVersion;
   uint8_t mID3MajorVersion;
   uint8_t mID3MinorVersion;
   uint8_t mID3Flags;
   uint32_t mID3Size;
 
   int64_t mDuration;
@@ -32,17 +56,17 @@ struct MP3Resource {
   // otherwise.
   int32_t mNumTrailingFrames;
   int32_t mBitrate;
   int32_t mSlotSize;
   int32_t mPrivate;
 
   // The first n frame offsets.
   std::vector<int32_t> mSyncOffsets;
-  nsRefPtr<MockMediaResource> mResource;
+  nsRefPtr<MockMP3MediaResource> mResource;
   nsRefPtr<MP3TrackDemuxer> mDemuxer;
 };
 
 class MP3DemuxerTest : public ::testing::Test {
 protected:
   void SetUp() override {
     {
       MP3Resource res;
@@ -61,17 +85,30 @@ protected:
       res.mSamplesPerFrame = 1152;
       res.mNumSamples = 1325952;
       res.mNumTrailingFrames = 2;
       res.mBitrate = 256000;
       res.mSlotSize = 1;
       res.mPrivate = 0;
       const int syncs[] = { 2151, 2987, 3823, 4659, 5495, 6331 };
       res.mSyncOffsets.insert(res.mSyncOffsets.begin(), syncs, syncs + 6);
+
+      // No content length can be estimated for CBR stream resources.
+      MP3Resource streamRes = res;
+      streamRes.mFileSize = -1;
+      streamRes.mDuration = -1;
+      streamRes.mDurationError = 0.0f;
+
+      res.mResource = new MockMP3MediaResource(res.mFilePath);
+      res.mDemuxer = new MP3TrackDemuxer(res.mResource);
       mTargets.push_back(res);
+
+      streamRes.mResource = new MockMP3StreamMediaResource(streamRes.mFilePath);
+      streamRes.mDemuxer = new MP3TrackDemuxer(streamRes.mResource);
+      mTargets.push_back(streamRes);
     }
 
     {
       MP3Resource res;
       res.mFilePath = "noise_vbr.mp3";
       res.mIsVBR = true;
       res.mFileSize = 583679;
       res.mMPEGLayer = 3;
@@ -86,23 +123,32 @@ protected:
       res.mSamplesPerFrame = 1152;
       res.mNumSamples = 1326575;
       res.mNumTrailingFrames = 3;
       res.mBitrate = 154000;
       res.mSlotSize = 1;
       res.mPrivate = 0;
       const int syncs[] = { 2231, 2648, 2752, 3796, 4318, 4735 };
       res.mSyncOffsets.insert(res.mSyncOffsets.begin(), syncs, syncs + 6);
+
+      // VBR stream resources contain header info on total frames numbers, which
+      // is used to estimate the total duration.
+      MP3Resource streamRes = res;
+      streamRes.mFileSize = -1;
+
+      res.mResource = new MockMP3MediaResource(res.mFilePath);
+      res.mDemuxer = new MP3TrackDemuxer(res.mResource);
       mTargets.push_back(res);
+
+      streamRes.mResource = new MockMP3StreamMediaResource(streamRes.mFilePath);
+      streamRes.mDemuxer = new MP3TrackDemuxer(streamRes.mResource);
+      mTargets.push_back(streamRes);
     }
 
     for (auto& target: mTargets) {
-      target.mResource = new MockMediaResource(target.mFilePath),
-      target.mDemuxer = new MP3TrackDemuxer(target.mResource);
-
       ASSERT_EQ(NS_OK, target.mResource->Open(nullptr));
       ASSERT_TRUE(target.mDemuxer->Init());
     }
   }
 
   std::vector<MP3Resource> mTargets;
 };
 
@@ -138,28 +184,28 @@ TEST_F(MP3DemuxerTest, VBRHeader) {
     }
   }
 }
 
 TEST_F(MP3DemuxerTest, FrameParsing) {
   for (const auto& target: mTargets) {
     nsRefPtr<MediaRawData> frameData(target.mDemuxer->DemuxSample());
     ASSERT_TRUE(frameData);
-    EXPECT_EQ(static_cast<int64_t>(target.mFileSize), target.mDemuxer->StreamLength());
+    EXPECT_EQ(target.mFileSize, target.mDemuxer->StreamLength());
 
     const auto& id3 = target.mDemuxer->ID3Header();
     ASSERT_TRUE(id3.IsValid());
 
-    uint64_t parsedLength = id3.Size();
-    uint64_t bitrateSum = 0;
-    uint32_t numFrames = 0;
-    uint32_t numSamples = 0;
+    int64_t parsedLength = id3.Size();
+    int64_t bitrateSum = 0;
+    int32_t numFrames = 0;
+    int32_t numSamples = 0;
 
     while (frameData) {
-      if (target.mSyncOffsets.size() > numFrames) {
+      if (static_cast<int64_t>(target.mSyncOffsets.size()) > numFrames) {
         // Test sync offsets.
         EXPECT_EQ(target.mSyncOffsets[numFrames], frameData->mOffset);
       }
 
       ++numFrames;
       parsedLength += frameData->mSize;
 
       const auto& frame = target.mDemuxer->LastFrame();
@@ -185,30 +231,32 @@ TEST_F(MP3DemuxerTest, FrameParsing) {
     }
 
     // TODO: find reference number which accounts for trailing headers.
     // EXPECT_EQ(target.mNumSamples / target.mSamplesPerFrame, numFrames);
     // EXPECT_EQ(target.mNumSamples, numSamples);
 
     // There may be trailing headers which we don't parse, so the stream length
     // is the upper bound.
-    EXPECT_GE(target.mFileSize, parsedLength);
+    if (target.mFileSize > 0) {
+      EXPECT_GE(target.mFileSize, parsedLength);
+    }
 
     if (target.mIsVBR) {
       ASSERT_TRUE(numFrames);
       EXPECT_EQ(target.mBitrate, static_cast<int32_t>(bitrateSum / numFrames));
     }
   }
 }
 
 TEST_F(MP3DemuxerTest, Duration) {
   for (const auto& target: mTargets) {
     nsRefPtr<MediaRawData> frameData(target.mDemuxer->DemuxSample());
     ASSERT_TRUE(frameData);
-    EXPECT_EQ(static_cast<int64_t>(target.mFileSize), target.mDemuxer->StreamLength());
+    EXPECT_EQ(target.mFileSize, target.mDemuxer->StreamLength());
 
     while (frameData) {
       EXPECT_NEAR(target.mDuration, target.mDemuxer->Duration().ToMicroseconds(),
                   target.mDurationError * target.mDuration);
 
       frameData = target.mDemuxer->DemuxSample();
     }
   }