mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-12-29 02:31:05 +00:00
229 lines
7.1 KiB
C++
229 lines
7.1 KiB
C++
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||
|
|
||
|
#include "gtest/gtest.h"
|
||
|
#include "VorbisTrackEncoder.h"
|
||
|
#include "WebMWriter.h"
|
||
|
#include "MediaStreamGraph.h"
|
||
|
|
||
|
using namespace mozilla;
|
||
|
|
||
|
class TestVorbisTrackEncoder : public VorbisTrackEncoder
|
||
|
{
|
||
|
public:
|
||
|
// Return true if it has successfully initialized the vorbis encoder.
|
||
|
bool TestVorbisCreation(int aChannels, int aSamplingRate)
|
||
|
{
|
||
|
if (Init(aChannels, aSamplingRate) == NS_OK) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
static bool
|
||
|
TestVorbisInit(int aChannels, int aSamplingRate)
|
||
|
{
|
||
|
TestVorbisTrackEncoder encoder;
|
||
|
return encoder.TestVorbisCreation(aChannels, aSamplingRate);
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
ReadLacing(const uint8_t* aInput, uint32_t aInputLength, uint32_t& aReadBytes)
|
||
|
{
|
||
|
aReadBytes = 0;
|
||
|
|
||
|
int packetSize = 0;
|
||
|
while (aReadBytes < aInputLength) {
|
||
|
if (aInput[aReadBytes] == 255) {
|
||
|
packetSize += 255;
|
||
|
aReadBytes++;
|
||
|
} else { // the last byte
|
||
|
packetSize += aInput[aReadBytes];
|
||
|
aReadBytes++;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return packetSize;
|
||
|
}
|
||
|
|
||
|
static bool
|
||
|
parseVorbisMetadata(nsTArray<uint8_t>& aData, int aChannels, int aRate)
|
||
|
{
|
||
|
uint32_t offset = 0;
|
||
|
// the first byte should be 2.
|
||
|
if (aData.ElementAt(0) != 2) {
|
||
|
return false;
|
||
|
}
|
||
|
offset = 1;
|
||
|
|
||
|
// Read the length of header and header_comm
|
||
|
uint32_t readbytes;
|
||
|
ogg_packet header;
|
||
|
ogg_packet header_comm;
|
||
|
ogg_packet header_code;
|
||
|
memset(&header, 0, sizeof(ogg_packet));
|
||
|
memset(&header_comm, 0, sizeof(ogg_packet));
|
||
|
memset(&header_code, 0, sizeof(ogg_packet));
|
||
|
|
||
|
int header_length;
|
||
|
int header_comm_length;
|
||
|
int header_code_length;
|
||
|
EXPECT_TRUE(offset < aData.Length());
|
||
|
header_length = ReadLacing(aData.Elements()+offset, aData.Length()-offset,
|
||
|
readbytes);
|
||
|
offset += readbytes;
|
||
|
EXPECT_TRUE(offset < aData.Length());
|
||
|
header_comm_length = ReadLacing(aData.Elements()+offset,
|
||
|
aData.Length()-offset, readbytes);
|
||
|
offset += readbytes;
|
||
|
EXPECT_TRUE(offset < aData.Length());
|
||
|
// The rest length is header_code.
|
||
|
header_code_length = aData.Length() - offset - header_length
|
||
|
- header_comm_length;
|
||
|
EXPECT_TRUE(header_code_length >= 32);
|
||
|
|
||
|
// Verify the three header packets by vorbis_synthesis_headerin.
|
||
|
// Raise the b_o_s (begin of stream) flag.
|
||
|
header.b_o_s = true;
|
||
|
header.packet = aData.Elements() + offset;
|
||
|
header.bytes = header_length;
|
||
|
offset += header_length;
|
||
|
header_comm.packet = aData.Elements() + offset;
|
||
|
header_comm.bytes = header_comm_length;
|
||
|
offset += header_comm_length;
|
||
|
header_code.packet = aData.Elements() + offset;
|
||
|
header_code.bytes = header_code_length;
|
||
|
|
||
|
vorbis_info vi;
|
||
|
vorbis_comment vc;
|
||
|
vorbis_info_init(&vi);
|
||
|
vorbis_comment_init(&vc);
|
||
|
|
||
|
EXPECT_TRUE(0 == vorbis_synthesis_headerin(&vi, &vc, &header));
|
||
|
|
||
|
EXPECT_TRUE(0 == vorbis_synthesis_headerin(&vi, &vc, &header_comm));
|
||
|
|
||
|
EXPECT_TRUE(0 == vorbis_synthesis_headerin(&vi, &vc, &header_code));
|
||
|
|
||
|
EXPECT_TRUE(vi.channels == aChannels);
|
||
|
EXPECT_TRUE(vi.rate == aRate);
|
||
|
|
||
|
vorbis_info_clear(&vi);
|
||
|
vorbis_comment_clear(&vc);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Test init function
|
||
|
TEST(VorbisTrackEncoder, Init)
|
||
|
{
|
||
|
// Channel number range test
|
||
|
// Expect false with 0 or negative channels of input signal.
|
||
|
EXPECT_FALSE(TestVorbisInit(0, 16000));
|
||
|
EXPECT_FALSE(TestVorbisInit(-1, 16000));
|
||
|
EXPECT_FALSE(TestVorbisInit(8 + 1, 16000));
|
||
|
|
||
|
// Sample rate and channel range test.
|
||
|
for (int i = 1; i <= 8; i++) {
|
||
|
EXPECT_FALSE(TestVorbisInit(i, -1));
|
||
|
EXPECT_FALSE(TestVorbisInit(i, 2000));
|
||
|
EXPECT_FALSE(TestVorbisInit(i, 4000));
|
||
|
EXPECT_FALSE(TestVorbisInit(i, 7999));
|
||
|
EXPECT_TRUE(TestVorbisInit(i, 8000));
|
||
|
EXPECT_TRUE(TestVorbisInit(i, 11000));
|
||
|
EXPECT_TRUE(TestVorbisInit(i, 16000));
|
||
|
EXPECT_TRUE(TestVorbisInit(i, 22050));
|
||
|
EXPECT_TRUE(TestVorbisInit(i, 32000));
|
||
|
EXPECT_TRUE(TestVorbisInit(i, 44100));
|
||
|
EXPECT_TRUE(TestVorbisInit(i, 48000));
|
||
|
EXPECT_TRUE(TestVorbisInit(i, 96000));
|
||
|
EXPECT_TRUE(TestVorbisInit(i, 192000));
|
||
|
EXPECT_FALSE(TestVorbisInit(i, 192001));
|
||
|
EXPECT_FALSE(TestVorbisInit(i, 200000 + 1));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Test metadata
|
||
|
TEST(VorbisTrackEncoder, Metadata)
|
||
|
{
|
||
|
// Initiate vorbis encoder.
|
||
|
TestVorbisTrackEncoder encoder;
|
||
|
int channels = 1;
|
||
|
int rate = 44100;
|
||
|
encoder.TestVorbisCreation(channels, rate);
|
||
|
|
||
|
RefPtr<TrackMetadataBase> meta = encoder.GetMetadata();
|
||
|
RefPtr<VorbisMetadata> vorbisMetadata(static_cast<VorbisMetadata*>(meta.get()));
|
||
|
|
||
|
// According to initialization parameters, verify the correctness
|
||
|
// of vorbisMetadata.
|
||
|
EXPECT_TRUE(vorbisMetadata->mChannels == channels);
|
||
|
EXPECT_TRUE(vorbisMetadata->mSamplingFrequency == rate);
|
||
|
EXPECT_TRUE(parseVorbisMetadata(vorbisMetadata->mData, channels, rate));
|
||
|
}
|
||
|
|
||
|
// Test encode function
|
||
|
TEST(VorbisTrackEncoder, EncodedFrame)
|
||
|
{
|
||
|
// Initiate vorbis encoder
|
||
|
TestVorbisTrackEncoder encoder;
|
||
|
int channels = 1;
|
||
|
int rate = 44100;
|
||
|
encoder.TestVorbisCreation(channels, rate);
|
||
|
|
||
|
// Generate 1 second samples.
|
||
|
// Reference PeerConnectionMedia.h::Fake_AudioGenerator
|
||
|
RefPtr<mozilla::SharedBuffer> samples =
|
||
|
mozilla::SharedBuffer::Create(rate * sizeof(AudioDataValue));
|
||
|
AudioDataValue* data = static_cast<AudioDataValue*>(samples->Data());
|
||
|
for (int i = 0; i < rate; i++) {
|
||
|
data[i] = ((i%8)*4000) - (7*4000)/2;
|
||
|
}
|
||
|
nsAutoTArray<const AudioDataValue*,1> channelData;
|
||
|
channelData.AppendElement(data);
|
||
|
AudioSegment segment;
|
||
|
segment.AppendFrames(samples.forget(), channelData, 44100);
|
||
|
|
||
|
// Track change notification.
|
||
|
encoder.NotifyQueuedTrackChanges(nullptr, 0, 0, 0, segment);
|
||
|
|
||
|
// Pull Encoded data back from encoder and verify encoded samples.
|
||
|
EncodedFrameContainer container;
|
||
|
EXPECT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
|
||
|
// Should have some encoded data.
|
||
|
EXPECT_TRUE(container.GetEncodedFrames().Length() > 0);
|
||
|
EXPECT_TRUE(container.GetEncodedFrames().ElementAt(0)->GetFrameData().Length()
|
||
|
> 0);
|
||
|
EXPECT_TRUE(container.GetEncodedFrames().ElementAt(0)->GetFrameType() ==
|
||
|
EncodedFrame::FrameType::VORBIS_AUDIO_FRAME);
|
||
|
// Encoded data doesn't have duration and timestamp.
|
||
|
EXPECT_TRUE(container.GetEncodedFrames().ElementAt(0)->GetDuration() == 0);
|
||
|
EXPECT_TRUE(container.GetEncodedFrames().ElementAt(0)->GetTimeStamp() == 0);
|
||
|
}
|
||
|
|
||
|
// EOS test
|
||
|
TEST(VorbisTrackEncoder, EncodeComplete)
|
||
|
{
|
||
|
// Initiate vorbis encoder
|
||
|
TestVorbisTrackEncoder encoder;
|
||
|
int channels = 1;
|
||
|
int rate = 44100;
|
||
|
encoder.TestVorbisCreation(channels, rate);
|
||
|
|
||
|
// Track end notification.
|
||
|
AudioSegment segment;
|
||
|
encoder.NotifyQueuedTrackChanges(nullptr, 0, 0,
|
||
|
MediaStreamListener::TRACK_EVENT_ENDED,
|
||
|
segment);
|
||
|
|
||
|
// Pull Encoded Data back from encoder. Since we had send out
|
||
|
// EOS to encoder, encoder.GetEncodedTrack should return
|
||
|
// NS_OK immidiately.
|
||
|
EncodedFrameContainer container;
|
||
|
EXPECT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
|
||
|
}
|