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 }