This source file includes following definitions.
- ComputePacketSize
- GetAccessUnits
- AppendAUD
- NewVideoConfig
- LoadStream
- GetPesTimestamps
- ProcessPesPackets
- EmitBuffer
- TEST_F
- TEST_F
- TEST_F
#include <algorithm>
#include <vector>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/memory_mapped_file.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/time/time.h"
#include "media/base/stream_parser_buffer.h"
#include "media/base/test_data_util.h"
#include "media/filters/h264_parser.h"
#include "media/formats/mp2t/es_parser_h264.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
class VideoDecoderConfig;
namespace mp2t {
namespace {
struct Packet {
size_t offset;
size_t size;
base::TimeDelta pts;
};
void ComputePacketSize(std::vector<Packet>& packets, size_t stream_size) {
for (size_t k = 0; k < packets.size() - 1; k++) {
DCHECK_GE(packets[k + 1].offset, packets[k].offset);
packets[k].size = packets[k + 1].offset - packets[k].offset;
}
packets[packets.size() - 1].size =
stream_size - packets[packets.size() - 1].offset;
}
std::vector<Packet> GetAccessUnits(const uint8* stream, size_t stream_size) {
std::vector<Packet> access_units;
bool start_access_unit = true;
size_t offset = 0;
while (true) {
off_t relative_offset = 0;
off_t start_code_size = 0;
bool success = H264Parser::FindStartCode(
&stream[offset], stream_size - offset,
&relative_offset, &start_code_size);
if (!success)
break;
offset += relative_offset;
if (start_access_unit) {
Packet cur_access_unit;
cur_access_unit.offset = offset;
access_units.push_back(cur_access_unit);
start_access_unit = false;
}
offset += start_code_size;
if (offset >= stream_size)
break;
int nal_unit_type = stream[offset] & 0x1f;
if (nal_unit_type == H264NALU::kIDRSlice ||
nal_unit_type == H264NALU::kNonIDRSlice) {
start_access_unit = true;
}
}
ComputePacketSize(access_units, stream_size);
return access_units;
}
void AppendAUD(
const uint8* stream, size_t stream_size,
const std::vector<Packet>& access_units,
std::vector<uint8>& stream_with_aud,
std::vector<Packet>& access_units_with_aud) {
uint8 aud[] = { 0x00, 0x00, 0x01, 0x09 };
stream_with_aud.resize(stream_size + access_units.size() * sizeof(aud));
access_units_with_aud.resize(access_units.size());
size_t offset = 0;
for (size_t k = 0; k < access_units.size(); k++) {
access_units_with_aud[k].offset = offset;
access_units_with_aud[k].size = access_units[k].size + sizeof(aud);
memcpy(&stream_with_aud[offset], aud, sizeof(aud));
offset += sizeof(aud);
memcpy(&stream_with_aud[offset],
&stream[access_units[k].offset], access_units[k].size);
offset += access_units[k].size;
}
}
}
class EsParserH264Test : public testing::Test {
public:
EsParserH264Test() : buffer_count_(0) {
}
virtual ~EsParserH264Test() {}
protected:
void LoadStream(const char* filename);
void GetPesTimestamps(std::vector<Packet>& pes_packets);
void ProcessPesPackets(const std::vector<Packet>& pes_packets,
bool force_timing);
std::vector<uint8> stream_;
std::vector<Packet> access_units_;
size_t buffer_count_;
private:
void EmitBuffer(scoped_refptr<StreamParserBuffer> buffer);
void NewVideoConfig(const VideoDecoderConfig& config) {
}
DISALLOW_COPY_AND_ASSIGN(EsParserH264Test);
};
void EsParserH264Test::LoadStream(const char* filename) {
base::FilePath file_path = GetTestDataFilePath(filename);
base::MemoryMappedFile stream_without_aud;
ASSERT_TRUE(stream_without_aud.Initialize(file_path))
<< "Couldn't open stream file: " << file_path.MaybeAsASCII();
std::vector<Packet> access_units_without_aud = GetAccessUnits(
stream_without_aud.data(), stream_without_aud.length());
ASSERT_GT(access_units_without_aud.size(), 0u);
AppendAUD(stream_without_aud.data(), stream_without_aud.length(),
access_units_without_aud,
stream_, access_units_);
for (size_t k = 0; k < access_units_.size(); k++)
access_units_[k].pts = base::TimeDelta::FromMilliseconds(k * 40u);
}
void EsParserH264Test::GetPesTimestamps(std::vector<Packet>& pes_packets) {
for (size_t k = 0; k < pes_packets.size(); k++) {
pes_packets[k].pts = base::TimeDelta::FromMilliseconds(-1);
}
size_t pes_idx = 0;
for (size_t k = 0; k < access_units_.size(); k++) {
for (; pes_idx < pes_packets.size(); pes_idx++) {
size_t pes_start = pes_packets[pes_idx].offset;
size_t pes_end = pes_packets[pes_idx].offset + pes_packets[pes_idx].size;
if (pes_start <= access_units_[k].offset &&
pes_end > access_units_[k].offset) {
pes_packets[pes_idx].pts = access_units_[k].pts;
break;
}
}
}
}
void EsParserH264Test::ProcessPesPackets(
const std::vector<Packet>& pes_packets,
bool force_timing) {
EsParserH264 es_parser(
base::Bind(&EsParserH264Test::NewVideoConfig, base::Unretained(this)),
base::Bind(&EsParserH264Test::EmitBuffer, base::Unretained(this)));
for (size_t k = 0; k < pes_packets.size(); k++) {
size_t cur_pes_offset = pes_packets[k].offset;
size_t cur_pes_size = pes_packets[k].size;
base::TimeDelta pts = kNoTimestamp();
base::TimeDelta dts = kNoTimestamp();
if (pes_packets[k].pts >= base::TimeDelta() || force_timing)
pts = pes_packets[k].pts;
ASSERT_TRUE(
es_parser.Parse(&stream_[cur_pes_offset], cur_pes_size, pts, dts));
}
es_parser.Flush();
}
void EsParserH264Test::EmitBuffer(scoped_refptr<StreamParserBuffer> buffer) {
ASSERT_LT(buffer_count_, access_units_.size());
EXPECT_EQ(buffer->timestamp(), access_units_[buffer_count_].pts);
buffer_count_++;
}
TEST_F(EsParserH264Test, OneAccessUnitPerPes) {
LoadStream("bear.h264");
std::vector<Packet> pes_packets(access_units_);
GetPesTimestamps(pes_packets);
ProcessPesPackets(pes_packets, false);
EXPECT_EQ(buffer_count_, access_units_.size());
}
TEST_F(EsParserH264Test, NonAlignedPesPacket) {
LoadStream("bear.h264");
std::vector<Packet> pes_packets;
Packet cur_pes_packet;
cur_pes_packet.offset = 0;
for (size_t k = 0; k < access_units_.size(); k++) {
pes_packets.push_back(cur_pes_packet);
cur_pes_packet.offset = access_units_[k].offset +
std::min<size_t>(487u, access_units_[k].size);
}
ComputePacketSize(pes_packets, stream_.size());
GetPesTimestamps(pes_packets);
ProcessPesPackets(pes_packets, false);
EXPECT_EQ(buffer_count_, access_units_.size());
}
TEST_F(EsParserH264Test, SeveralPesPerAccessUnit) {
LoadStream("bear.h264");
size_t min_access_unit_size = stream_.size();
for (size_t k = 0; k < access_units_.size(); k++) {
if (min_access_unit_size >= access_units_[k].size)
min_access_unit_size = access_units_[k].size;
}
size_t pes_size = 512;
if (min_access_unit_size < pes_size)
pes_size = min_access_unit_size;
std::vector<Packet> pes_packets;
Packet cur_pes_packet;
cur_pes_packet.offset = 0;
while (cur_pes_packet.offset < stream_.size()) {
pes_packets.push_back(cur_pes_packet);
cur_pes_packet.offset += pes_size;
}
ComputePacketSize(pes_packets, stream_.size());
GetPesTimestamps(pes_packets);
ProcessPesPackets(pes_packets, false);
EXPECT_EQ(buffer_count_, access_units_.size());
buffer_count_ = 0;
ProcessPesPackets(pes_packets, true);
EXPECT_EQ(buffer_count_, access_units_.size());
}
}
}