2
* Copyright (C) 2016 Canonical, Ltd.
4
* This program is free software: you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License version 3, as published
6
* by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranties of
10
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11
* PURPOSE. See the GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License along
14
* with this program. If not, see <http://www.gnu.org/licenses/>.
18
#include <gtest/gtest.h>
22
#include <mcs/streaming/mpegtspacketizer.h>
25
static constexpr uint8_t kMPEGTSPacketLength = 188;
26
static constexpr uint8_t kMPEGTSStartByte = 0x47;
27
static const uint8_t csd0[] = {
29
0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x0a, 0xf8, 0x41, 0xa2,
31
0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x38, 0x80
33
static const uint8_t slice_header[] = {
34
// Slice header comes first
35
0x00, 0x00, 0x00, 0x01, 0x05, 0x88, 0x84, 0x21, 0xa0,
38
mcs::video::Buffer::Ptr CreateFrame(int size) {
39
auto buffer = mcs::video::Buffer::Create(size + sizeof(slice_header));
40
::memcpy(buffer->Data(), slice_header, sizeof(slice_header));
44
class MPEGTSPacketMatcher {
46
MPEGTSPacketMatcher(const mcs::video::Buffer::Ptr &buffer) :
50
MPEGTSPacketMatcher(const MPEGTSPacketMatcher &other) :
51
buffer_(other.buffer_) {
55
EXPECT_EQ(0x47, buffer_->Data()[0]);
58
void ExpectPackets(int count) {
59
// One MPEGTS element has a constant length
60
EXPECT_EQ(kMPEGTSPacketLength * count, buffer_->Length());
62
// Split into multiple packets so that those can be process
64
for (int n = 0; n < count; n++) {
65
auto packet = mcs::video::Buffer::Create(kMPEGTSPacketLength);
66
::memcpy(packet->Data(), buffer_->Data() + (n * kMPEGTSPacketLength), kMPEGTSPacketLength);
67
packets_.push_back(MPEGTSPacketMatcher(packet));
71
void ExpectPID(uint16_t expected_pid) {
72
uint16_t pid = ((buffer_->Data()[1] ^ 0x40) << 8) | buffer_->Data()[2];
73
EXPECT_EQ(expected_pid, pid);
76
void ExpectPaddingBytesAndContinuityCounter(uint8_t counter) {
77
EXPECT_EQ(0x30 | counter, buffer_->Data()[3]);
80
void ExpectNoPaddingBytesAndContinuityCounter(uint8_t counter) {
81
EXPECT_EQ(0x10 | counter, buffer_->Data()[3]);
84
void ExpectData(uint8_t *data, size_t length) {
85
// What we have supplied into the packtizer should be now placed at the end of
86
// the element we got back from the packetizer.
87
EXPECT_EQ(0, memcmp(buffer_->Data() + (buffer_->Length() - length),
91
void ExpectByte(unsigned int n, uint8_t expected_byte) {
92
EXPECT_EQ(expected_byte, buffer_->Data()[n]);
95
MPEGTSPacketMatcher& At(int n) {
96
return packets_.at(n);
100
mcs::video::Buffer::Ptr buffer_;
101
std::vector<MPEGTSPacketMatcher> packets_;
106
TEST(MPEGTSPacketizer, AddTrackWithoutAnythingSet) {
107
auto packetizer = mcs::streaming::MPEGTSPacketizer::Create();
108
auto id = packetizer->AddTrack(mcs::streaming::MPEGTSPacketizer::TrackFormat{});
112
TEST(MPEGTSPacketizer, AddValidTrack) {
113
auto packetizer = mcs::streaming::MPEGTSPacketizer::Create();
114
auto id = packetizer->AddTrack(mcs::streaming::MPEGTSPacketizer::TrackFormat{"video/avc"});
118
TEST(MPEGTSPacketizer, TryMoreThanOneValidTrack) {
119
auto packetizer = mcs::streaming::MPEGTSPacketizer::Create();
120
auto id = packetizer->AddTrack(mcs::streaming::MPEGTSPacketizer::TrackFormat{"video/avc"});
122
for (int i = 0; i < 15; i++) {
123
id = packetizer->AddTrack(mcs::streaming::MPEGTSPacketizer::TrackFormat{"video/avc"});
126
id = packetizer->AddTrack(mcs::streaming::MPEGTSPacketizer::TrackFormat{"video/avc"});
130
TEST(MPEGTSPacketizer, SubmitAndProcessCodecSpecificData) {
131
auto packetizer = mcs::streaming::MPEGTSPacketizer::Create();
132
auto id = packetizer->AddTrack(mcs::streaming::MPEGTSPacketizer::TrackFormat{"video/avc"});
134
auto buffer = mcs::video::Buffer::Create(sizeof(csd0));
135
::memcpy(buffer->Data(), csd0, sizeof(csd0));
137
mcs::video::Buffer::Ptr out;
139
packetizer->Packetize(id, buffer, &out);
141
MPEGTSPacketMatcher matcher(out);
143
matcher.ExpectPackets(1);
144
matcher.At(0).ExpectPackets(1);
145
matcher.At(0).ExpectValid();
146
matcher.At(0).ExpectPID(0x1011);
147
matcher.At(0).ExpectPaddingBytesAndContinuityCounter(0);
148
matcher.At(0).ExpectData(buffer->Data(), buffer->Length());
150
EXPECT_GE(0, out->Timestamp());
153
TEST(MPEGTSPacketizer, EmitPCRandPATandPMT) {
154
auto packetizer = mcs::streaming::MPEGTSPacketizer::Create();
155
auto id = packetizer->AddTrack(mcs::streaming::MPEGTSPacketizer::TrackFormat{"video/avc"});
157
mcs::video::Buffer::Ptr out;
158
auto buffer = CreateFrame(100);
160
packetizer->Packetize(id, buffer, &out, mcs::streaming::Packetizer::kEmitPCR |
161
mcs::streaming::Packetizer::kEmitPATandPMT);
163
MPEGTSPacketMatcher matcher(out);
165
// We should have four packets now:
169
// 4. Actual TS packet
170
matcher.ExpectPackets(4);
172
matcher.At(0).ExpectValid();
173
matcher.At(0).ExpectPID(0);
174
matcher.At(0).ExpectNoPaddingBytesAndContinuityCounter(1);
176
matcher.At(1).ExpectValid();
177
matcher.At(1).ExpectPID(0x100);
178
matcher.At(1).ExpectNoPaddingBytesAndContinuityCounter(1);
180
matcher.At(2).ExpectValid();
181
matcher.At(2).ExpectPID(0x1000);
182
// It doesn't really set a continuity counter for the PCR
183
// TS packet so just compare the static value we expect here.
184
matcher.At(2).ExpectByte(3, 0x20);
186
matcher.At(3).ExpectValid();
187
matcher.At(3).ExpectPID(0x1011);
188
matcher.At(3).ExpectPaddingBytesAndContinuityCounter(0);
189
matcher.At(3).ExpectData(buffer->Data(), buffer->Length());
191
EXPECT_GE(0, out->Timestamp());
194
TEST(MPEGTSPacketizer, IncreasingContinuityCounter) {
195
auto packetizer = mcs::streaming::MPEGTSPacketizer::Create();
196
auto id = packetizer->AddTrack(mcs::streaming::MPEGTSPacketizer::TrackFormat{"video/avc"});
198
// Make sure we looper over 15 here as that is used for the continuity counter
199
// for PAT/PMT and PCR but shouldn't be used here.
200
for (int n = 0; n < 20; n++) {
201
mcs::video::Buffer::Ptr out;
202
auto buffer = CreateFrame(100);
204
packetizer->Packetize(id, buffer, &out, mcs::streaming::Packetizer::kEmitPCR |
205
mcs::streaming::Packetizer::kEmitPATandPMT);
207
MPEGTSPacketMatcher matcher(out);
209
matcher.ExpectPackets(4);
211
matcher.At(0).ExpectValid();
212
matcher.At(0).ExpectPID(0);
213
// Continuity counter starts a 1 and goes up to 15
214
matcher.At(0).ExpectNoPaddingBytesAndContinuityCounter((n + 1) % 16);
216
matcher.At(1).ExpectValid();
217
matcher.At(1).ExpectPID(0x100);
218
// Continuity counter starts a 1 and goes up to 15
219
matcher.At(1).ExpectNoPaddingBytesAndContinuityCounter((n + 1) % 16);
221
matcher.At(2).ExpectValid();
222
matcher.At(2).ExpectPID(0x1000);
223
// It doesn't really set a continuity counter for the PCR
224
// TS packet so just compare the static value we expect here.
225
matcher.At(2).ExpectByte(3, 0x20);
227
matcher.At(3).ExpectValid();
228
matcher.At(3).ExpectPID(0x1011);
229
matcher.At(3).ExpectPaddingBytesAndContinuityCounter(n);
230
matcher.At(3).ExpectData(buffer->Data(), buffer->Length());