tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TestMuxer.cpp (7878B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "ContainerWriter.h"
      8 #include "EncodedFrame.h"
      9 #include "Muxer.h"
     10 #include "OpusTrackEncoder.h"
     11 #include "WebMWriter.h"
     12 #include "gmock/gmock.h"
     13 #include "gtest/gtest.h"
     14 
     15 using namespace mozilla;
     16 using media::TimeUnit;
     17 using testing::_;
     18 using testing::ElementsAre;
     19 using testing::Return;
     20 using testing::StaticAssertTypeEq;
     21 
     22 static RefPtr<TrackMetadataBase> CreateOpusMetadata(int32_t aChannels,
     23                                                    float aSamplingFrequency,
     24                                                    size_t aIdHeaderSize,
     25                                                    size_t aCommentHeaderSize) {
     26  auto opusMetadata = MakeRefPtr<OpusMetadata>();
     27  opusMetadata->mChannels = aChannels;
     28  opusMetadata->mSamplingFrequency = aSamplingFrequency;
     29  opusMetadata->mIdHeader.SetLength(aIdHeaderSize);
     30  for (size_t i = 0; i < opusMetadata->mIdHeader.Length(); i++) {
     31    opusMetadata->mIdHeader[i] = 0;
     32  }
     33  opusMetadata->mCommentHeader.SetLength(aCommentHeaderSize);
     34  for (size_t i = 0; i < opusMetadata->mCommentHeader.Length(); i++) {
     35    opusMetadata->mCommentHeader[i] = 0;
     36  }
     37  return opusMetadata;
     38 }
     39 
     40 static RefPtr<TrackMetadataBase> CreateVP8Metadata(int32_t aWidth,
     41                                                   int32_t aHeight) {
     42  auto vp8Metadata = MakeRefPtr<VP8Metadata>();
     43  vp8Metadata->mWidth = aWidth;
     44  vp8Metadata->mDisplayWidth = aWidth;
     45  vp8Metadata->mHeight = aHeight;
     46  vp8Metadata->mDisplayHeight = aHeight;
     47  return vp8Metadata;
     48 }
     49 
     50 static RefPtr<EncodedFrame> CreateFrame(EncodedFrame::FrameType aType,
     51                                        const TimeUnit& aTime,
     52                                        const TimeUnit& aDuration,
     53                                        size_t aDataSize) {
     54  auto data = MakeRefPtr<EncodedFrame::FrameData>();
     55  data->SetLength(aDataSize);
     56  if (aType == EncodedFrame::OPUS_AUDIO_FRAME) {
     57    // Opus duration is in samples, so figure out how many samples will put us
     58    // closest to aDurationUs without going over.
     59    return MakeRefPtr<EncodedFrame>(aTime,
     60                                    TimeUnitToFrames(aDuration, 48000).value(),
     61                                    48000, aType, std::move(data));
     62  }
     63  return MakeRefPtr<EncodedFrame>(
     64      aTime, TimeUnitToFrames(aDuration, USECS_PER_S).value(), USECS_PER_S,
     65      aType, std::move(data));
     66 }
     67 
     68 class MockContainerWriter : public ContainerWriter {
     69 public:
     70  MOCK_METHOD2(WriteEncodedTrack,
     71               nsresult(const nsTArray<RefPtr<EncodedFrame>>&, uint32_t));
     72  MOCK_METHOD1(SetMetadata,
     73               nsresult(const nsTArray<RefPtr<TrackMetadataBase>>&));
     74  MOCK_METHOD0(IsWritingComplete, bool());
     75  MOCK_METHOD2(GetContainerData,
     76               nsresult(nsTArray<nsTArray<uint8_t>>*, uint32_t));
     77 };
     78 
     79 TEST(MuxerTest, AudioOnly)
     80 {
     81  MediaQueue<EncodedFrame> audioQueue;
     82  MediaQueue<EncodedFrame> videoQueue;
     83  videoQueue.Finish();
     84  MockContainerWriter* writer = new MockContainerWriter();
     85  Muxer muxer(WrapUnique<ContainerWriter>(writer), audioQueue, videoQueue);
     86 
     87  // Prepare data
     88 
     89  auto opusMeta = CreateOpusMetadata(1, 48000, 16, 16);
     90  auto audioFrame =
     91      CreateFrame(EncodedFrame::OPUS_AUDIO_FRAME, TimeUnit::FromSeconds(0),
     92                  TimeUnit::FromSeconds(0.2), 4096);
     93 
     94  // Expectations
     95 
     96  EXPECT_CALL(*writer, SetMetadata(ElementsAre(opusMeta)))
     97      .WillOnce(Return(NS_OK));
     98  EXPECT_CALL(*writer, WriteEncodedTrack(ElementsAre(audioFrame),
     99                                         ContainerWriter::END_OF_STREAM))
    100      .WillOnce(Return(NS_OK));
    101  EXPECT_CALL(*writer, GetContainerData(_, ContainerWriter::GET_HEADER))
    102      .WillOnce(Return(NS_OK));
    103  EXPECT_CALL(*writer, GetContainerData(_, ContainerWriter::FLUSH_NEEDED))
    104      .WillOnce(Return(NS_OK));
    105  EXPECT_CALL(*writer, IsWritingComplete()).Times(0);
    106 
    107  // Test
    108 
    109  EXPECT_EQ(muxer.SetMetadata(nsTArray<RefPtr<TrackMetadataBase>>({opusMeta})),
    110            NS_OK);
    111  audioQueue.Push(audioFrame);
    112  audioQueue.Finish();
    113  nsTArray<nsTArray<uint8_t>> buffers;
    114  EXPECT_EQ(muxer.GetData(&buffers), NS_OK);
    115 }
    116 
    117 TEST(MuxerTest, AudioVideo)
    118 {
    119  MediaQueue<EncodedFrame> audioQueue;
    120  MediaQueue<EncodedFrame> videoQueue;
    121  MockContainerWriter* writer = new MockContainerWriter();
    122  Muxer muxer(WrapUnique<ContainerWriter>(writer), audioQueue, videoQueue);
    123 
    124  // Prepare data
    125 
    126  auto opusMeta = CreateOpusMetadata(1, 48000, 16, 16);
    127  auto vp8Meta = CreateVP8Metadata(640, 480);
    128  auto audioFrame =
    129      CreateFrame(EncodedFrame::OPUS_AUDIO_FRAME, TimeUnit::FromSeconds(0),
    130                  TimeUnit::FromSeconds(0.2), 4096);
    131  auto videoFrame =
    132      CreateFrame(EncodedFrame::VP8_I_FRAME, TimeUnit::FromSeconds(0),
    133                  TimeUnit::FromSeconds(0.05), 65536);
    134 
    135  // Expectations
    136 
    137  EXPECT_CALL(*writer, SetMetadata(ElementsAre(opusMeta, vp8Meta)))
    138      .WillOnce(Return(NS_OK));
    139  EXPECT_CALL(*writer, WriteEncodedTrack(ElementsAre(videoFrame, audioFrame),
    140                                         ContainerWriter::END_OF_STREAM))
    141      .WillOnce(Return(NS_OK));
    142  EXPECT_CALL(*writer, GetContainerData(_, ContainerWriter::GET_HEADER))
    143      .WillOnce(Return(NS_OK));
    144  EXPECT_CALL(*writer, GetContainerData(_, ContainerWriter::FLUSH_NEEDED))
    145      .WillOnce(Return(NS_OK));
    146  EXPECT_CALL(*writer, IsWritingComplete()).Times(0);
    147 
    148  // Test
    149 
    150  EXPECT_EQ(muxer.SetMetadata(
    151                nsTArray<RefPtr<TrackMetadataBase>>({opusMeta, vp8Meta})),
    152            NS_OK);
    153  audioQueue.Push(audioFrame);
    154  audioQueue.Finish();
    155  videoQueue.Push(videoFrame);
    156  videoQueue.Finish();
    157  nsTArray<nsTArray<uint8_t>> buffers;
    158  EXPECT_EQ(muxer.GetData(&buffers), NS_OK);
    159 }
    160 
    161 TEST(MuxerTest, AudioVideoOutOfOrder)
    162 {
    163  MediaQueue<EncodedFrame> audioQueue;
    164  MediaQueue<EncodedFrame> videoQueue;
    165  MockContainerWriter* writer = new MockContainerWriter();
    166  Muxer muxer(WrapUnique<ContainerWriter>(writer), audioQueue, videoQueue);
    167 
    168  // Prepare data
    169 
    170  auto opusMeta = CreateOpusMetadata(1, 48000, 16, 16);
    171  auto vp8Meta = CreateVP8Metadata(640, 480);
    172  auto a0 =
    173      CreateFrame(EncodedFrame::OPUS_AUDIO_FRAME, TimeUnit::FromMicroseconds(0),
    174                  TimeUnit::FromMicroseconds(48), 4096);
    175  auto v0 =
    176      CreateFrame(EncodedFrame::VP8_I_FRAME, TimeUnit::FromMicroseconds(0),
    177                  TimeUnit::FromMicroseconds(50), 65536);
    178  auto a48 = CreateFrame(EncodedFrame::OPUS_AUDIO_FRAME,
    179                         TimeUnit::FromMicroseconds(48),
    180                         TimeUnit::FromMicroseconds(48), 4096);
    181  auto v50 =
    182      CreateFrame(EncodedFrame::VP8_I_FRAME, TimeUnit::FromMicroseconds(50),
    183                  TimeUnit::FromMicroseconds(50), 65536);
    184 
    185  // Expectations
    186 
    187  EXPECT_CALL(*writer, SetMetadata(ElementsAre(opusMeta, vp8Meta)))
    188      .WillOnce(Return(NS_OK));
    189  EXPECT_CALL(*writer, WriteEncodedTrack(ElementsAre(v0, a0, a48, v50),
    190                                         ContainerWriter::END_OF_STREAM))
    191      .WillOnce(Return(NS_OK));
    192  EXPECT_CALL(*writer, GetContainerData(_, ContainerWriter::GET_HEADER))
    193      .WillOnce(Return(NS_OK));
    194  EXPECT_CALL(*writer, GetContainerData(_, ContainerWriter::FLUSH_NEEDED))
    195      .WillOnce(Return(NS_OK));
    196  EXPECT_CALL(*writer, IsWritingComplete()).Times(0);
    197 
    198  // Test
    199 
    200  EXPECT_EQ(muxer.SetMetadata(
    201                nsTArray<RefPtr<TrackMetadataBase>>({opusMeta, vp8Meta})),
    202            NS_OK);
    203  audioQueue.Push(a0);
    204  videoQueue.Push(v0);
    205  videoQueue.Push(v50);
    206  videoQueue.Finish();
    207  audioQueue.Push(a48);
    208  audioQueue.Finish();
    209  nsTArray<nsTArray<uint8_t>> buffers;
    210  EXPECT_EQ(muxer.GetData(&buffers), NS_OK);
    211 }