Commit 53cd0d12 authored by Eugene Zemtsov's avatar Eugene Zemtsov Committed by Commit Bot

Serialize AVCDecoderConfigurationRecord

Bug: 1122955
Change-Id: I0d31e92fedfa8cbaf52445b1d727bb19401369c5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2381255Reviewed-by: default avatarDale Curtis <dalecurtis@chromium.org>
Reviewed-by: default avatarThomas Guilbert <tguilbert@chromium.org>
Commit-Queue: Eugene Zemtsov <eugene@chromium.org>
Cr-Commit-Position: refs/heads/master@{#803659}
parent 6f7d9da5
......@@ -8,6 +8,7 @@
#include <memory>
#include <utility>
#include "base/big_endian.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
......@@ -718,6 +719,82 @@ bool AVCDecoderConfigurationRecord::ParseInternal(BufferReader* reader,
return true;
}
bool AVCDecoderConfigurationRecord::Serialize(std::vector<uint8_t>& output) {
// See ISO/IEC 14496-15 5.3.3.1.2 for the format description
constexpr uint8_t sps_list_size_mask = (1 << 5) - 1; // 5 bits
if (sps_list.size() > sps_list_size_mask)
return false;
constexpr uint8_t pps_list_size_mask = 0xff;
if (pps_list.size() > pps_list_size_mask)
return false;
if (length_size > 4)
return false;
// Calculating total size of the buffer we'll need for serialization
size_t expected_size =
1 + // configurationVersion
1 + // AVCProfileIndication
1 + // profile_compatibility
1 + // AVCLevelIndication
1 + // lengthSizeMinusOne
1 + // numOfSequenceParameterSets, i.e. length of sps_list
1; // numOfPictureParameterSets, i.e. length of pps_list
constexpr size_t max_vector_size = (1 << 16) - 1; // 2 bytes
for (auto& sps : sps_list) {
expected_size += 2; // 2 bytes for sequenceParameterSetLength
if (sps.size() > max_vector_size)
return false;
expected_size += sps.size();
}
for (auto& pps : pps_list) {
expected_size += 2; // 2 bytes for pictureParameterSetLength;
if (pps.size() > max_vector_size)
return false;
expected_size += pps.size();
}
output.clear();
output.resize(expected_size);
base::BigEndianWriter writer(reinterpret_cast<char*>(output.data()),
output.size());
bool result = true;
// configurationVersion
result &= writer.WriteU8(version);
// AVCProfileIndication
result &= writer.WriteU8(profile_indication);
// profile_compatibility
result &= writer.WriteU8(profile_compatibility);
// AVCLevelIndication
result &= writer.WriteU8(avc_level);
// lengthSizeMinusOne
uint8_t length_size_minus_one = (length_size - 1) | 0xfc;
result &= writer.WriteU8(length_size_minus_one);
// numOfSequenceParameterSets
uint8_t sps_size = sps_list.size() | ~sps_list_size_mask;
result &= writer.WriteU8(sps_size);
// sequenceParameterSetNALUnits
for (auto& sps : sps_list) {
result &= writer.WriteU16(sps.size());
writer.WriteBytes(sps.data(), sps.size());
}
// numOfPictureParameterSets
uint8_t pps_size = pps_list.size();
result &= writer.WriteU8(pps_size);
// pictureParameterSetNALUnit
for (auto& pps : pps_list) {
result &= writer.WriteU16(pps.size());
writer.WriteBytes(pps.data(), pps.size());
}
return result;
}
#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
VPCodecConfigurationRecord::VPCodecConfigurationRecord()
......
......@@ -227,6 +227,7 @@ struct MEDIA_EXPORT AVCDecoderConfigurationRecord : Box {
// in |data|.
// Returns true if |data| was successfully parsed.
bool Parse(const uint8_t* data, int data_size);
bool Serialize(std::vector<uint8_t>& output);
uint8_t version;
uint8_t profile_indication;
......
......@@ -10,6 +10,7 @@
#include <algorithm>
#include <set>
#include "base/big_endian.h"
#include "media/formats/mp4/box_definitions.h"
namespace media {
......@@ -27,12 +28,9 @@ bool BufferReader::Read1(uint8_t* v) {
template<typename T> bool BufferReader::Read(T* v) {
RCHECK(HasBytes(sizeof(T)));
T tmp = 0;
for (size_t i = 0; i < sizeof(T); i++) {
tmp <<= 8;
tmp += buf_[pos_++];
}
*v = tmp;
// MPEG-4 uses big endian byte order
base::ReadBigEndian(reinterpret_cast<const char*>(buf_ + pos_), v);
pos_ += sizeof(T);
return true;
}
......
......@@ -486,5 +486,63 @@ TEST_F(BoxReaderTest, OutsideOfBoxRead) {
EXPECT_FALSE(reader->Read4(&value));
}
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
TEST_F(BoxReaderTest, AVCDecoderConfigurationRecordTakenFromMp4) {
std::vector<uint8_t> test_data{
0x1, // configurationVersion
0x64, // AVCProfileIndication
0x0, // profile_compatibility
0xc, // AVCLevelIndication
0xff, // lengthSizeMinusOne
0xe1, // numOfSequenceParameterSets = 1
0x0, 0x19, // sequenceParameterSetLength = 25
// sequenceParameterSet
0x67, 0x64, 0x0, 0xc, 0xac, 0xd9, 0x41, 0x41, 0xfb, 0x1, 0x10, 0x0, 0x0,
0x3, 0x0, 0x10, 0x0, 0x0, 0x3, 0x1, 0x40, 0xf1, 0x42, 0x99, 0x60,
0x1, // numOfPictureParameterSets
0x0, 0x6, // pictureParameterSetLength = 6
0x68, 0xeb, 0xe3, 0xcb, 0x22, 0xc0,
// Profile specific params are not supported yet, skip last bytes
// 0xfd, 0xf8, 0xf8, 0x0
};
AVCDecoderConfigurationRecord record;
EXPECT_TRUE(record.Parse(test_data.data(), test_data.size()));
EXPECT_EQ(record.version, 1);
EXPECT_EQ(record.profile_indication, 0x64);
EXPECT_EQ(record.profile_compatibility, 0);
EXPECT_EQ(record.avc_level, 0xc);
EXPECT_EQ(record.length_size, 4);
EXPECT_EQ(record.sps_list.size(), 1ull);
EXPECT_EQ(record.sps_list[0].size(), 25ull);
EXPECT_EQ(record.pps_list.size(), 1ull);
EXPECT_EQ(record.pps_list[0].size(), 6ull);
std::vector<uint8_t> output;
EXPECT_TRUE(record.Serialize(output));
EXPECT_EQ(output.size(), test_data.size());
ASSERT_THAT(output, testing::ElementsAreArray(test_data));
}
TEST_F(BoxReaderTest, AVCDecoderConfigurationRecordTakenFromStream) {
std::vector<uint8_t> test_data{
0x01, 0x4D, 0x00, 0x15, 0xff, 0xe1, 0x00, 0x2F, 0x67, 0x4D, 0x40,
0x15, 0x96, 0x52, 0x02, 0x83, 0xF6, 0x02, 0xA1, 0x00, 0x00, 0x03,
0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x28, 0xE0, 0x60, 0x03, 0x0D,
0x40, 0x00, 0x49, 0x3E, 0x7F, 0x18, 0xE3, 0x03, 0x00, 0x18, 0x6A,
0x00, 0x02, 0x49, 0xF3, 0xF8, 0xC7, 0x0E, 0xD0, 0xB1, 0x68, 0x90,
0x01, 0x00, 0x04, 0x68, 0xEB, 0x73, 0x52};
AVCDecoderConfigurationRecord record;
EXPECT_TRUE(record.Parse(test_data.data(), test_data.size()));
std::vector<uint8_t> output;
EXPECT_TRUE(record.Serialize(output));
ASSERT_THAT(output, testing::ElementsAreArray(test_data));
}
#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
} // namespace mp4
} // namespace media
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment