Move AVCDecoderConfiguration parsing to media/filters

Change-Id: I7daa616e53bdef2206ce145f907b8f55cde87740
This commit is contained in:
KongQun Yang 2015-10-26 17:52:57 -07:00 committed by Gerrit Code Review
parent 3842a5b43c
commit 8fc7f51d81
19 changed files with 354 additions and 323 deletions

View File

@ -92,25 +92,5 @@ std::string VideoStreamInfo::ToString() const {
nalu_length_size_); nalu_length_size_);
} }
std::string VideoStreamInfo::GetCodecString(VideoCodec codec,
uint8_t profile,
uint8_t compatible_profiles,
uint8_t level) {
switch (codec) {
case kCodecVP8:
return "vp8";
case kCodecVP9:
return "vp9";
case kCodecH264: {
const uint8_t bytes[] = {profile, compatible_profiles, level};
return "avc1." +
base::StringToLowerASCII(base::HexEncode(bytes, arraysize(bytes)));
}
default:
NOTIMPLEMENTED() << "Unknown Codec: " << codec;
return "unknown";
}
}
} // namespace media } // namespace media
} // namespace edash_packager } // namespace edash_packager

View File

@ -28,9 +28,6 @@ enum VideoCodec {
class VideoStreamInfo : public StreamInfo { class VideoStreamInfo : public StreamInfo {
public: public:
/// Construct an initialized video stream info object. /// Construct an initialized video stream info object.
/// If @a codec is @a kCodecH264 and either @pixel_width and @pixel_height is
/// 0 (unknown), then this tries to parse @extra_data to extract the pixel
/// width and height from it.
/// @param pixel_width is the width of the pixel. 0 if unknown. /// @param pixel_width is the width of the pixel. 0 if unknown.
/// @param pixel_height is the height of the pixels. 0 if unknown. /// @param pixel_height is the height of the pixels. 0 if unknown.
VideoStreamInfo(int track_id, VideoStreamInfo(int track_id,
@ -72,13 +69,6 @@ class VideoStreamInfo : public StreamInfo {
void set_pixel_width(uint32_t pixel_width) { pixel_width_ = pixel_width; } void set_pixel_width(uint32_t pixel_width) { pixel_width_ = pixel_width; }
void set_pixel_height(uint32_t pixel_height) { pixel_height_ = pixel_height; } void set_pixel_height(uint32_t pixel_height) { pixel_height_ = pixel_height; }
/// @param profile,compatible_profiles,level are only used by H.264 codec.
/// @return The codec string.
static std::string GetCodecString(VideoCodec codec,
uint8_t profile,
uint8_t compatible_profiles,
uint8_t level);
private: private:
~VideoStreamInfo() override; ~VideoStreamInfo() override;

View File

@ -41,9 +41,7 @@ VideoStreamInfoParameters GetDefaultVideoStreamInfoParams() {
const uint32_t kTimeScale = 10; const uint32_t kTimeScale = 10;
const uint64_t kVideoStreamDuration = 200; const uint64_t kVideoStreamDuration = 200;
const VideoCodec kH264Codec = kCodecH264; const VideoCodec kH264Codec = kCodecH264;
const uint8_t kH264Profile = 1; const char* kCodecString = "avc1.010101";
const uint8_t kH264CompatibleProfile = 1;
const uint8_t kH264Level = 1;
const char* kLanuageUndefined = "und"; const char* kLanuageUndefined = "und";
const uint16_t kWidth = 720; const uint16_t kWidth = 720;
const uint16_t kHeight = 480; const uint16_t kHeight = 480;
@ -57,8 +55,7 @@ VideoStreamInfoParameters GetDefaultVideoStreamInfoParams() {
params.time_scale = kTimeScale; params.time_scale = kTimeScale;
params.duration = kVideoStreamDuration; params.duration = kVideoStreamDuration;
params.codec = kH264Codec; params.codec = kH264Codec;
params.codec_string = VideoStreamInfo::GetCodecString( params.codec_string = kCodecString;
kCodecH264, kH264Profile, kH264CompatibleProfile, kH264Level);
params.language = kLanuageUndefined; params.language = kLanuageUndefined;
params.width = kWidth; params.width = kWidth;
params.height = kHeight; params.height = kHeight;

View File

@ -0,0 +1,77 @@
// Copyright 2015 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "packager/media/filters/avc_decoder_configuration.h"
#include "packager/base/stl_util.h"
#include "packager/base/strings/string_number_conversions.h"
#include "packager/base/strings/string_util.h"
#include "packager/media/base/buffer_reader.h"
#include "packager/media/filters/h264_parser.h"
#include "packager/media/formats/mp4/rcheck.h"
namespace edash_packager {
namespace media {
AVCDecoderConfiguration::AVCDecoderConfiguration()
: version_(0),
profile_indication_(0),
profile_compatibility_(0),
avc_level_(0),
length_size_(0) {}
AVCDecoderConfiguration::~AVCDecoderConfiguration() {}
bool AVCDecoderConfiguration::Parse(const std::vector<uint8_t>& data) {
BufferReader reader(vector_as_array(&data), data.size());
RCHECK(reader.Read1(&version_) && version_ == 1 &&
reader.Read1(&profile_indication_) &&
reader.Read1(&profile_compatibility_) && reader.Read1(&avc_level_));
uint8_t length_size_minus_one;
RCHECK(reader.Read1(&length_size_minus_one));
length_size_ = (length_size_minus_one & 0x3) + 1;
uint8_t num_sps;
RCHECK(reader.Read1(&num_sps));
num_sps &= 0x1f;
if (num_sps < 1) {
LOG(ERROR) << "No SPS found.";
return false;
}
uint16_t sps_length = 0;
RCHECK(reader.Read2(&sps_length));
H264Parser parser;
int sps_id = 0;
RCHECK(parser.ParseSPSFromArray(reader.data() + reader.pos(), sps_length,
&sps_id) == H264Parser::kOk);
return ExtractResolutionFromSps(*parser.GetSPS(sps_id), &coded_width_,
&coded_height_, &pixel_width_,
&pixel_height_);
// It is unlikely to have more than one SPS in practice. Also there's
// no way to change the {coded,pixel}_{width,height} dynamically from
// VideoStreamInfo. So skip the rest (if there are any).
}
std::string AVCDecoderConfiguration::GetCodecString() const {
return GetCodecString(profile_indication_, profile_compatibility_,
avc_level_);
}
std::string AVCDecoderConfiguration::GetCodecString(
uint8_t profile_indication,
uint8_t profile_compatibility,
uint8_t avc_level) {
const uint8_t bytes[] = {profile_indication, profile_compatibility,
avc_level};
return "avc1." +
base::StringToLowerASCII(base::HexEncode(bytes, arraysize(bytes)));
}
} // namespace media
} // namespace edash_packager

View File

@ -0,0 +1,67 @@
// Copyright 2015 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#ifndef MEDIA_FILTERS_AVC_DECODER_CONFIGURATION_H_
#define MEDIA_FILTERS_AVC_DECODER_CONFIGURATION_H_
#include <stdint.h>
#include <string>
#include <vector>
#include "packager/base/macros.h"
namespace edash_packager {
namespace media {
/// Class for parsing AVC decoder configuration.
class AVCDecoderConfiguration {
public:
AVCDecoderConfiguration();
~AVCDecoderConfiguration();
/// Parses input to extract AVC decoder configuration data.
/// @return false if there is parsing errors.
bool Parse(const std::vector<uint8_t>& data);
/// @return The codec string.
std::string GetCodecString() const;
uint8_t version() const { return version_; }
uint8_t profile_indication() const { return profile_indication_; }
uint8_t profile_compatibility() const { return profile_compatibility_; }
uint8_t avc_level() const { return avc_level_; }
uint8_t length_size() const { return length_size_; }
uint32_t coded_width() const { return coded_width_; }
uint32_t coded_height() const { return coded_height_; }
uint32_t pixel_width() const { return pixel_width_; }
uint32_t pixel_height() const { return pixel_height_; }
/// Static version of GetCodecString.
/// @return The codec string.
static std::string GetCodecString(uint8_t profile_indication,
uint8_t profile_compatibility,
uint8_t avc_level);
private:
uint8_t version_;
uint8_t profile_indication_;
uint8_t profile_compatibility_;
uint8_t avc_level_;
uint8_t length_size_;
// Extracted from SPS.
uint32_t coded_width_;
uint32_t coded_height_;
uint32_t pixel_width_;
uint32_t pixel_height_;
DISALLOW_COPY_AND_ASSIGN(AVCDecoderConfiguration);
};
} // namespace media
} // namespace edash_packager
#endif // MEDIA_FILTERS_AVC_DECODER_CONFIGURATION_H_

View File

@ -0,0 +1,54 @@
// Copyright 2015 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "packager/media/filters/avc_decoder_configuration.h"
#include <gtest/gtest.h>
namespace edash_packager {
namespace media {
TEST(AVCDecoderConfigurationTest, Success) {
const uint8_t kAvcDecoderConfigurationData[] = {
0x01, 0x64, 0x00, 0x1E, 0xFF, 0xE1, 0x00, 0x1D, 0x67, 0x64, 0x00, 0x1E,
0xAC, 0xD9, 0x40, 0xB4, 0x2F, 0xF9, 0x7F, 0xF0, 0x00, 0x80, 0x00, 0x91,
0x00, 0x00, 0x03, 0x03, 0xE9, 0x00, 0x00, 0xEA, 0x60, 0x0F, 0x16, 0x2D,
0x96, 0x01, 0x00, 0x06, 0x68, 0xEB, 0xE3, 0xCB, 0x22, 0xC0};
AVCDecoderConfiguration avc_config;
ASSERT_TRUE(avc_config.Parse(std::vector<uint8_t>(
kAvcDecoderConfigurationData,
kAvcDecoderConfigurationData + arraysize(kAvcDecoderConfigurationData))));
EXPECT_EQ(1u, avc_config.version());
EXPECT_EQ(0x64, avc_config.profile_indication());
EXPECT_EQ(0u, avc_config.profile_compatibility());
EXPECT_EQ(0x1E, avc_config.avc_level());
EXPECT_EQ(4u, avc_config.length_size());
EXPECT_EQ(720u, avc_config.coded_width());
EXPECT_EQ(360u, avc_config.coded_height());
EXPECT_EQ(8u, avc_config.pixel_width());
EXPECT_EQ(9u, avc_config.pixel_height());
EXPECT_EQ("avc1.64001e", avc_config.GetCodecString());
}
TEST(AVCDecoderConfigurationTest, FailOnInsufficientData) {
const uint8_t kAvcDecoderConfigurationData[] = {0x01, 0x64, 0x00, 0x1E};
AVCDecoderConfiguration avc_config;
ASSERT_FALSE(avc_config.Parse(std::vector<uint8_t>(
kAvcDecoderConfigurationData,
kAvcDecoderConfigurationData + arraysize(kAvcDecoderConfigurationData))));
}
TEST(AVCDecoderConfigurationTest, GetCodecString) {
EXPECT_EQ("avc1.123456",
AVCDecoderConfiguration::GetCodecString(0x12, 0x34, 0x56));
}
} // namespace media
} // namespace edash_packager

View File

@ -13,6 +13,8 @@
'target_name': 'filters', 'target_name': 'filters',
'type': '<(component)', 'type': '<(component)',
'sources': [ 'sources': [
'avc_decoder_configuration.cc',
'avc_decoder_configuration.h',
'h264_bit_reader.cc', 'h264_bit_reader.cc',
'h264_bit_reader.h', 'h264_bit_reader.h',
'h264_byte_to_unit_stream_converter.cc', 'h264_byte_to_unit_stream_converter.cc',
@ -28,6 +30,7 @@
'target_name': 'filters_unittest', 'target_name': 'filters_unittest',
'type': '<(gtest_target_type)', 'type': '<(gtest_target_type)',
'sources': [ 'sources': [
'avc_decoder_configuration_unittest.cc',
'h264_bit_reader_unittest.cc', 'h264_bit_reader_unittest.cc',
'h264_byte_to_unit_stream_converter_unittest.cc', 'h264_byte_to_unit_stream_converter_unittest.cc',
'h264_parser_unittest.cc', 'h264_parser_unittest.cc',

View File

@ -12,62 +12,6 @@
namespace edash_packager { namespace edash_packager {
namespace media { namespace media {
#define RCHECK(x) \
do { \
if (!(x)) { \
LOG(ERROR) << "Failure while parsing AVCDecoderConfig: " << #x; \
return false; \
} \
} while (0)
bool ExtractResolutionFromDecoderConfig(const uint8_t* avc_decoder_config_data,
size_t avc_decoder_config_data_size,
uint32_t* coded_width,
uint32_t* coded_height,
uint32_t* pixel_width,
uint32_t* pixel_height) {
BufferReader reader(avc_decoder_config_data, avc_decoder_config_data_size);
uint8_t value = 0;
// version check, must be 1.
RCHECK(reader.Read1(&value));
RCHECK(value == 1);
// Skip avc profile, profile compatibility, avc level, and length size.
RCHECK(reader.SkipBytes(4));
// Reserved and num sps.
RCHECK(reader.Read1(&value));
const uint8_t num_sps = value & 0x1F;
if (num_sps < 1) {
LOG(ERROR) << "No SPS found.";
return false;
}
uint16_t sps_length = 0;
RCHECK(reader.Read2(&sps_length));
return ExtractResolutionFromSpsData(reader.data() + reader.pos(), sps_length,
coded_width, coded_height, pixel_width,
pixel_height);
// It is unlikely to have more than one SPS in practice. Also there's
// no way to change the {coded,pixel}_{width,height} dynamically from
// VideoStreamInfo. So skip the rest (if there are any).
}
bool ExtractResolutionFromSpsData(const uint8_t* sps_data,
size_t sps_data_size,
uint32_t* coded_width,
uint32_t* coded_height,
uint32_t* pixel_width,
uint32_t* pixel_height) {
H264Parser parser;
int sps_id;
RCHECK(parser.ParseSPSFromArray(sps_data, sps_data_size, &sps_id) ==
H264Parser::kOk);
return ExtractResolutionFromSps(*parser.GetSPS(sps_id), coded_width,
coded_height, pixel_width, pixel_height);
}
// Implemented according to ISO/IEC 14496-10:2005 7.4.2.1 Sequence parameter set // Implemented according to ISO/IEC 14496-10:2005 7.4.2.1 Sequence parameter set
// RBSP semantics. // RBSP semantics.
bool ExtractResolutionFromSps(const H264SPS& sps, bool ExtractResolutionFromSps(const H264SPS& sps,
@ -133,8 +77,6 @@ bool ExtractResolutionFromSps(const H264SPS& sps,
return true; return true;
} }
#undef RCHECK
bool H264SliceHeader::IsPSlice() const { bool H264SliceHeader::IsPSlice() const {
return (slice_type % 5 == kPSlice); return (slice_type % 5 == kPSlice);
} }

View File

@ -17,28 +17,9 @@
namespace edash_packager { namespace edash_packager {
namespace media { namespace media {
// |avc_decoder_config_data| must be AVCDecoderConfigurationRecord specified
// in ISO/IEC 14496-15.
// On success, |coded_width| and |coded_height| contains coded resolution after
// cropping; |pixel_width:pixel_height| contains pixel aspect ratio, 1:1 is
// assigned if it is not present.
bool ExtractResolutionFromDecoderConfig(const uint8_t* avc_decoder_config_data,
size_t avc_decoder_config_data_size,
uint32_t* coded_width,
uint32_t* coded_height,
uint32_t* pixel_width,
uint32_t* pixel_height);
// |sps_data| must be a valid SPS specified in ISO/IEC 14496-10.
// On success, |coded_width| and |coded_height| contains coded resolution after // On success, |coded_width| and |coded_height| contains coded resolution after
// cropping; |pixel_width:pixel_height| contains pixel aspect ratio, 1:1 is // cropping; |pixel_width:pixel_height| contains pixel aspect ratio, 1:1 is
// assigned if it is not present in SPS. // assigned if it is not present in SPS.
bool ExtractResolutionFromSpsData(const uint8_t* sps_data,
size_t sps_data_size,
uint32_t* coded_width,
uint32_t* coded_height,
uint32_t* pixel_width,
uint32_t* pixel_height);
struct H264SPS; struct H264SPS;
bool ExtractResolutionFromSps(const H264SPS& sps, bool ExtractResolutionFromSps(const H264SPS& sps,
uint32_t* coded_width, uint32_t* coded_width,

View File

@ -65,37 +65,22 @@ TEST(H264ParserTest, StreamFileParsing) {
} }
} }
TEST(H264ParserTest, ExtractResolutionFromDecoderConfig) {
const uint8_t kDecoderConfig[] = {
0x01, 0x64, 0x00, 0x1E, 0xFF, 0xE1, 0x00, 0x1D, 0x67, 0x64, 0x00, 0x1E,
0xAC, 0xD9, 0x40, 0xB4, 0x2F, 0xF9, 0x7F, 0xF0, 0x00, 0x80, 0x00, 0x91,
0x00, 0x00, 0x03, 0x03, 0xE9, 0x00, 0x00, 0xEA, 0x60, 0x0F, 0x16, 0x2D,
0x96, 0x01, 0x00, 0x06, 0x68, 0xEB, 0xE3, 0xCB, 0x22, 0xC0};
uint32_t coded_width = 0;
uint32_t coded_height = 0;
uint32_t pixel_width = 0;
uint32_t pixel_height = 0;
ASSERT_TRUE(ExtractResolutionFromDecoderConfig(
kDecoderConfig, arraysize(kDecoderConfig), &coded_width, &coded_height,
&pixel_width, &pixel_height));
EXPECT_EQ(720u, coded_width);
EXPECT_EQ(360u, coded_height);
EXPECT_EQ(8u, pixel_width);
EXPECT_EQ(9u, pixel_height);
}
TEST(H264ParserTest, ExtractResolutionFromSpsData) { TEST(H264ParserTest, ExtractResolutionFromSpsData) {
const uint8_t kSps[] = {0x67, 0x64, 0x00, 0x1E, 0xAC, 0xD9, 0x40, 0xB4, const uint8_t kSps[] = {0x67, 0x64, 0x00, 0x1E, 0xAC, 0xD9, 0x40, 0xB4,
0x2F, 0xF9, 0x7F, 0xF0, 0x00, 0x80, 0x00, 0x91, 0x2F, 0xF9, 0x7F, 0xF0, 0x00, 0x80, 0x00, 0x91,
0x00, 0x00, 0x03, 0x03, 0xE9, 0x00, 0x00, 0xEA, 0x00, 0x00, 0x03, 0x03, 0xE9, 0x00, 0x00, 0xEA,
0x60, 0x0F, 0x16, 0x2D, 0x96}; 0x60, 0x0F, 0x16, 0x2D, 0x96};
H264Parser parser;
int sps_id = 0;
ASSERT_EQ(H264Parser::kOk,
parser.ParseSPSFromArray(kSps, arraysize(kSps), &sps_id));
uint32_t coded_width = 0; uint32_t coded_width = 0;
uint32_t coded_height = 0; uint32_t coded_height = 0;
uint32_t pixel_width = 0; uint32_t pixel_width = 0;
uint32_t pixel_height = 0; uint32_t pixel_height = 0;
ASSERT_TRUE(ExtractResolutionFromSpsData(kSps, arraysize(kSps), &coded_width, ASSERT_TRUE(ExtractResolutionFromSps(*parser.GetSPS(sps_id), &coded_width,
&coded_height, &pixel_width, &coded_height, &pixel_width,
&pixel_height)); &pixel_height));
EXPECT_EQ(720u, coded_width); EXPECT_EQ(720u, coded_width);
@ -110,11 +95,16 @@ TEST(H264ParserTest, ExtractResolutionFromSpsDataWithCropping) {
0x9F, 0x01, 0x10, 0x00, 0x00, 0x03, 0x00, 0x10, 0x00, 0x9F, 0x01, 0x10, 0x00, 0x00, 0x03, 0x00, 0x10, 0x00,
0x00, 0x03, 0x03, 0x00, 0xF1, 0x42, 0x99, 0x60}; 0x00, 0x03, 0x03, 0x00, 0xF1, 0x42, 0x99, 0x60};
H264Parser parser;
int sps_id = 0;
ASSERT_EQ(H264Parser::kOk,
parser.ParseSPSFromArray(kSps, arraysize(kSps), &sps_id));
uint32_t coded_width = 0; uint32_t coded_width = 0;
uint32_t coded_height = 0; uint32_t coded_height = 0;
uint32_t pixel_width = 0; uint32_t pixel_width = 0;
uint32_t pixel_height = 0; uint32_t pixel_height = 0;
ASSERT_TRUE(ExtractResolutionFromSpsData(kSps, arraysize(kSps), &coded_width, ASSERT_TRUE(ExtractResolutionFromSps(*parser.GetSPS(sps_id), &coded_width,
&coded_height, &pixel_width, &coded_height, &pixel_width,
&pixel_height)); &pixel_height));
EXPECT_EQ(320u, coded_width); EXPECT_EQ(320u, coded_width);

View File

@ -12,6 +12,7 @@
#include "packager/media/base/offset_byte_queue.h" #include "packager/media/base/offset_byte_queue.h"
#include "packager/media/base/timestamp.h" #include "packager/media/base/timestamp.h"
#include "packager/media/base/video_stream_info.h" #include "packager/media/base/video_stream_info.h"
#include "packager/media/filters/avc_decoder_configuration.h"
#include "packager/media/filters/h264_byte_to_unit_stream_converter.h" #include "packager/media/filters/h264_byte_to_unit_stream_converter.h"
#include "packager/media/filters/h264_parser.h" #include "packager/media/filters/h264_parser.h"
#include "packager/media/formats/mp2t/mp2t_common.h" #include "packager/media/formats/mp2t/mp2t_common.h"
@ -361,8 +362,7 @@ bool EsParserH264::UpdateVideoDecoderConfig(const H264SPS* sps) {
kMpeg2Timescale, kMpeg2Timescale,
kInfiniteDuration, kInfiniteDuration,
kCodecH264, kCodecH264,
VideoStreamInfo::GetCodecString(kCodecH264, AVCDecoderConfiguration::GetCodecString(decoder_config_record[1],
decoder_config_record[1],
decoder_config_record[2], decoder_config_record[2],
decoder_config_record[3]), decoder_config_record[3]),
std::string(), std::string(),

View File

@ -35,6 +35,8 @@ const uint32_t kVideoResolution = 0x00480000; // 72 dpi.
const uint16_t kVideoFrameCount = 1; const uint16_t kVideoFrameCount = 1;
const uint16_t kVideoDepth = 0x0018; const uint16_t kVideoDepth = 0x0018;
const uint32_t kCompressorNameSize = 32u;
// Utility functions to check if the 64bit integers can fit in 32bit integer. // Utility functions to check if the 64bit integers can fit in 32bit integer.
bool IsFitIn32Bits(uint64_t a) { bool IsFitIn32Bits(uint64_t a) {
return a <= std::numeric_limits<uint32_t>::max(); return a <= std::numeric_limits<uint32_t>::max();
@ -873,63 +875,25 @@ uint32_t HandlerReference::ComputeSize() {
return atom_size; return atom_size;
} }
AVCDecoderConfigurationRecord::AVCDecoderConfigurationRecord() CodecConfigurationRecord::CodecConfigurationRecord() : box_type(FOURCC_NULL) {}
: version(0), CodecConfigurationRecord::~CodecConfigurationRecord() {}
profile_indication(0), FourCC CodecConfigurationRecord::BoxType() const {
profile_compatibility(0), // CodecConfigurationRecord should be parsed according to format recovered in
avc_level(0), // VideoSampleEntry. |box_type| is determined dynamically there.
length_size(0) {} return box_type;
}
AVCDecoderConfigurationRecord::~AVCDecoderConfigurationRecord() {} bool CodecConfigurationRecord::ReadWrite(BoxBuffer* buffer) {
FourCC AVCDecoderConfigurationRecord::BoxType() const { return FOURCC_AVCC; }
bool AVCDecoderConfigurationRecord::ReadWrite(BoxBuffer* buffer) {
RCHECK(Box::ReadWrite(buffer)); RCHECK(Box::ReadWrite(buffer));
if (buffer->Reading()) { if (buffer->Reading()) {
RCHECK(buffer->ReadWriteVector(&data, buffer->Size() - buffer->Pos())); RCHECK(buffer->ReadWriteVector(&data, buffer->Size() - buffer->Pos()));
BufferReader buffer_reader(&data[0], data.size());
return ParseData(&buffer_reader);
} else { } else {
RCHECK(buffer->ReadWriteVector(&data, data.size())); RCHECK(buffer->ReadWriteVector(&data, data.size()));
} }
return true; return true;
} }
bool AVCDecoderConfigurationRecord::ParseData(BufferReader* reader) { uint32_t CodecConfigurationRecord::ComputeSize() {
RCHECK(reader->Read1(&version) && version == 1 &&
reader->Read1(&profile_indication) &&
reader->Read1(&profile_compatibility) &&
reader->Read1(&avc_level));
uint8_t length_size_minus_one;
RCHECK(reader->Read1(&length_size_minus_one));
length_size = (length_size_minus_one & 0x3) + 1;
uint8_t num_sps;
RCHECK(reader->Read1(&num_sps));
num_sps &= 0x1f;
sps_list.resize(num_sps);
for (int i = 0; i < num_sps; i++) {
uint16_t sps_length;
RCHECK(reader->Read2(&sps_length) &&
reader->ReadToVector(&sps_list[i], sps_length));
}
uint8_t num_pps;
RCHECK(reader->Read1(&num_pps));
pps_list.resize(num_pps);
for (int i = 0; i < num_pps; i++) {
uint16_t pps_length;
RCHECK(reader->Read2(&pps_length) &&
reader->ReadToVector(&pps_list[i], pps_length));
}
return true;
}
uint32_t AVCDecoderConfigurationRecord::ComputeSize() {
atom_size = 0; atom_size = 0;
if (!data.empty()) if (!data.empty())
atom_size = kBoxSize + data.size(); atom_size = kBoxSize + data.size();
@ -1009,10 +973,16 @@ bool VideoSampleEntry::ReadWrite(BoxBuffer* buffer) {
} }
} }
if (format == FOURCC_AVC1 || const FourCC actual_format = GetActualFormat();
(format == FOURCC_ENCV && sinf.format.format == FOURCC_AVC1)) { switch (actual_format) {
RCHECK(buffer->ReadWriteChild(&avcc)); case FOURCC_AVC1:
codec_config_record.box_type = FOURCC_AVCC;
break;
default:
LOG(ERROR) << FourCCToString(actual_format) << " is not supported.";
return false;
} }
RCHECK(buffer->ReadWriteChild(&codec_config_record));
RCHECK(buffer->TryReadWriteChild(&pixel_aspect)); RCHECK(buffer->TryReadWriteChild(&pixel_aspect));
return true; return true;
} }
@ -1022,7 +992,7 @@ uint32_t VideoSampleEntry::ComputeSize() {
sizeof(height) + sizeof(kVideoResolution) * 2 + sizeof(height) + sizeof(kVideoResolution) * 2 +
sizeof(kVideoFrameCount) + sizeof(kVideoDepth) + sizeof(kVideoFrameCount) + sizeof(kVideoDepth) +
pixel_aspect.ComputeSize() + sinf.ComputeSize() + pixel_aspect.ComputeSize() + sinf.ComputeSize() +
avcc.ComputeSize() + 32 + // 32 bytes comparessor_name. codec_config_record.ComputeSize() + kCompressorNameSize +
6 + 4 + 16 + 2; // 6 + 4 bytes reserved, 16 + 2 bytes predefined. 6 + 4 + 16 + 2; // 6 + 4 bytes reserved, 16 + 2 bytes predefined.
return atom_size; return atom_size;
} }

View File

@ -5,7 +5,6 @@
#ifndef MEDIA_FORMATS_MP4_BOX_DEFINITIONS_H_ #ifndef MEDIA_FORMATS_MP4_BOX_DEFINITIONS_H_
#define MEDIA_FORMATS_MP4_BOX_DEFINITIONS_H_ #define MEDIA_FORMATS_MP4_BOX_DEFINITIONS_H_
#include <string>
#include <vector> #include <vector>
#include "packager/media/formats/mp4/aac_audio_specific_config.h" #include "packager/media/formats/mp4/aac_audio_specific_config.h"
@ -165,27 +164,12 @@ struct HandlerReference : FullBox {
TrackType type; TrackType type;
}; };
struct AVCDecoderConfigurationRecord : Box { struct CodecConfigurationRecord : Box {
DECLARE_BOX_METHODS(AVCDecoderConfigurationRecord); DECLARE_BOX_METHODS(CodecConfigurationRecord);
bool ParseData(BufferReader* reader);
// Contains full avc decoder configuration record as defined in iso14496-15 FourCC box_type;
// 5.2.4.1, including possible extension bytes described in paragraph 3. // Contains full codec configuration record, including possible extension boxes.
// Known fields defined in the spec are also parsed and included in this
// structure.
std::vector<uint8_t> data; std::vector<uint8_t> data;
uint8_t version;
uint8_t profile_indication;
uint8_t profile_compatibility;
uint8_t avc_level;
uint8_t length_size;
typedef std::vector<uint8_t> SPS;
typedef std::vector<uint8_t> PPS;
std::vector<SPS> sps_list;
std::vector<PPS> pps_list;
}; };
struct PixelAspectRatioBox : Box { struct PixelAspectRatioBox : Box {
@ -197,6 +181,10 @@ struct PixelAspectRatioBox : Box {
struct VideoSampleEntry : Box { struct VideoSampleEntry : Box {
DECLARE_BOX_METHODS(VideoSampleEntry); DECLARE_BOX_METHODS(VideoSampleEntry);
// Returns actual format of this sample entry.
FourCC GetActualFormat() const {
return format == FOURCC_ENCV ? sinf.format.format : format;
}
FourCC format; FourCC format;
uint16_t data_reference_index; uint16_t data_reference_index;
@ -205,9 +193,7 @@ struct VideoSampleEntry : Box {
PixelAspectRatioBox pixel_aspect; PixelAspectRatioBox pixel_aspect;
ProtectionSchemeInfo sinf; ProtectionSchemeInfo sinf;
CodecConfigurationRecord codec_config_record;
// Currently expected to be present regardless of format.
AVCDecoderConfigurationRecord avcc;
}; };
struct ElementaryStreamDescriptor : FullBox { struct ElementaryStreamDescriptor : FullBox {
@ -219,6 +205,10 @@ struct ElementaryStreamDescriptor : FullBox {
struct AudioSampleEntry : Box { struct AudioSampleEntry : Box {
DECLARE_BOX_METHODS(AudioSampleEntry); DECLARE_BOX_METHODS(AudioSampleEntry);
// Returns actual format of this sample entry.
FourCC GetActualFormat() const {
return format == FOURCC_ENCA ? sinf.format.format : format;
}
FourCC format; FourCC format;
uint16_t data_reference_index; uint16_t data_reference_index;

View File

@ -165,8 +165,8 @@ inline bool operator==(const HandlerReference& lhs,
return lhs.type == rhs.type; return lhs.type == rhs.type;
} }
inline bool operator==(const AVCDecoderConfigurationRecord& lhs, inline bool operator==(const CodecConfigurationRecord& lhs,
const AVCDecoderConfigurationRecord& rhs) { const CodecConfigurationRecord& rhs) {
return lhs.data == rhs.data; return lhs.data == rhs.data;
} }
@ -181,7 +181,7 @@ inline bool operator==(const VideoSampleEntry& lhs,
lhs.data_reference_index == rhs.data_reference_index && lhs.data_reference_index == rhs.data_reference_index &&
lhs.width == rhs.width && lhs.height == rhs.height && lhs.width == rhs.width && lhs.height == rhs.height &&
lhs.pixel_aspect == rhs.pixel_aspect && lhs.sinf == rhs.sinf && lhs.pixel_aspect == rhs.pixel_aspect && lhs.sinf == rhs.sinf &&
lhs.avcc == rhs.avcc; lhs.codec_config_record == rhs.codec_config_record;
} }
inline bool operator==(const ESDescriptor& lhs, const ESDescriptor& rhs) { inline bool operator==(const ESDescriptor& lhs, const ESDescriptor& rhs) {

View File

@ -274,26 +274,24 @@ class BoxDefinitionsTestGeneral : public testing::Test {
void Modify(PixelAspectRatioBox* pasp) { pasp->v_spacing *= 8; } void Modify(PixelAspectRatioBox* pasp) { pasp->v_spacing *= 8; }
void Fill(AVCDecoderConfigurationRecord* avcc) { void Fill(CodecConfigurationRecord* codec_config_record) {
const uint8_t kAvccData[] = { const uint8_t kAvccData[] = {
0x01, 0x64, 0x00, 0x1f, 0xff, 0xe1, 0x00, 0x18, 0x67, 0x64, 0x00, 0x01, 0x64, 0x00, 0x1f, 0xff, 0xe1, 0x00, 0x18, 0x67, 0x64, 0x00,
0x1f, 0xac, 0xd9, 0x40, 0x50, 0x05, 0xbb, 0x01, 0x10, 0x00, 0x00, 0x1f, 0xac, 0xd9, 0x40, 0x50, 0x05, 0xbb, 0x01, 0x10, 0x00, 0x00,
0x3e, 0x90, 0x00, 0x0e, 0xa6, 0x00, 0xf1, 0x83, 0x19, 0x60, 0x01, 0x3e, 0x90, 0x00, 0x0e, 0xa6, 0x00, 0xf1, 0x83, 0x19, 0x60, 0x01,
0x00, 0x06, 0x68, 0xeb, 0xe3, 0xcb, 0x22, 0xc0}; 0x00, 0x06, 0x68, 0xeb, 0xe3, 0xcb, 0x22, 0xc0};
BufferReader buffer_reader(kAvccData, arraysize(kAvccData)); codec_config_record->data.assign(kAvccData,
CHECK(avcc->ParseData(&buffer_reader)); kAvccData + arraysize(kAvccData));
avcc->data.assign(kAvccData, kAvccData + arraysize(kAvccData));
} }
void Modify(AVCDecoderConfigurationRecord* avcc) { void Modify(CodecConfigurationRecord* codec_config_record) {
const uint8_t kAvccData[] = { const uint8_t kAvccData[] = {
0x01, 0x64, 0x00, 0x1e, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x01, 0x64, 0x00, 0x1e, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00,
0x1e, 0xac, 0xd9, 0x40, 0xa0, 0x2f, 0xf9, 0x70, 0x11, 0x00, 0x00, 0x1e, 0xac, 0xd9, 0x40, 0xa0, 0x2f, 0xf9, 0x70, 0x11, 0x00, 0x00,
0x03, 0x03, 0xe9, 0x00, 0x00, 0xea, 0x60, 0x0f, 0x16, 0x2d, 0x96, 0x03, 0x03, 0xe9, 0x00, 0x00, 0xea, 0x60, 0x0f, 0x16, 0x2d, 0x96,
0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c}; 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
BufferReader buffer_reader(kAvccData, arraysize(kAvccData)); codec_config_record->data.assign(kAvccData,
CHECK(avcc->ParseData(&buffer_reader)); kAvccData + arraysize(kAvccData));
avcc->data.assign(kAvccData, kAvccData + arraysize(kAvccData));
} }
void Fill(VideoSampleEntry* encv) { void Fill(VideoSampleEntry* encv) {
@ -303,12 +301,12 @@ class BoxDefinitionsTestGeneral : public testing::Test {
encv->height = 600; encv->height = 600;
Fill(&encv->pixel_aspect); Fill(&encv->pixel_aspect);
Fill(&encv->sinf); Fill(&encv->sinf);
Fill(&encv->avcc); Fill(&encv->codec_config_record);
} }
void Modify(VideoSampleEntry* encv) { void Modify(VideoSampleEntry* encv) {
encv->height += 600; encv->height += 600;
Modify(&encv->avcc); Modify(&encv->codec_config_record);
} }
void Fill(ElementaryStreamDescriptor* esds) { void Fill(ElementaryStreamDescriptor* esds) {
@ -725,7 +723,7 @@ class BoxDefinitionsTestGeneral : public testing::Test {
bool IsOptional(const ProtectionSchemeInfo* box) { return true; } bool IsOptional(const ProtectionSchemeInfo* box) { return true; }
bool IsOptional(const EditList* box) { return true; } bool IsOptional(const EditList* box) { return true; }
bool IsOptional(const Edit* box) { return true; } bool IsOptional(const Edit* box) { return true; }
bool IsOptional(const AVCDecoderConfigurationRecord* box) { return true; } bool IsOptional(const CodecConfigurationRecord* box) { return true; }
bool IsOptional(const PixelAspectRatioBox* box) { return true; } bool IsOptional(const PixelAspectRatioBox* box) { return true; }
bool IsOptional(const ElementaryStreamDescriptor* box) { return true; } bool IsOptional(const ElementaryStreamDescriptor* box) { return true; }
bool IsOptional(const CompositionTimeToSample* box) { return true; } bool IsOptional(const CompositionTimeToSample* box) { return true; }
@ -755,7 +753,7 @@ typedef testing::Types<
EditList, EditList,
Edit, Edit,
HandlerReference, HandlerReference,
AVCDecoderConfigurationRecord, CodecConfigurationRecord,
PixelAspectRatioBox, PixelAspectRatioBox,
VideoSampleEntry, VideoSampleEntry,
ElementaryStreamDescriptor, ElementaryStreamDescriptor,

View File

@ -20,7 +20,7 @@
#include "packager/media/base/video_stream_info.h" #include "packager/media/base/video_stream_info.h"
#include "packager/media/file/file.h" #include "packager/media/file/file.h"
#include "packager/media/file/file_closer.h" #include "packager/media/file/file_closer.h"
#include "packager/media/filters/h264_parser.h" #include "packager/media/filters/avc_decoder_configuration.h"
#include "packager/media/formats/mp4/box_definitions.h" #include "packager/media/formats/mp4/box_definitions.h"
#include "packager/media/formats/mp4/box_reader.h" #include "packager/media/formats/mp4/box_reader.h"
#include "packager/media/formats/mp4/es_descriptor.h" #include "packager/media/formats/mp4/es_descriptor.h"
@ -355,73 +355,70 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
desc_idx = 0; desc_idx = 0;
const VideoSampleEntry& entry = samp_descr.video_entries[desc_idx]; const VideoSampleEntry& entry = samp_descr.video_entries[desc_idx];
if (!(entry.format == FOURCC_AVC1 || uint32_t coded_width = entry.width;
(entry.format == FOURCC_ENCV && uint32_t coded_height = entry.height;
entry.sinf.format.format == FOURCC_AVC1))) { uint32_t pixel_width = entry.pixel_aspect.h_spacing;
LOG(ERROR) << "Unsupported video format 0x" uint32_t pixel_height = entry.pixel_aspect.v_spacing;
<< std::hex << entry.format << " in stsd box."; if (pixel_width == 0 && pixel_height == 0) {
pixel_width = 1;
pixel_height = 1;
}
std::string codec_string;
uint8_t nalu_length_size = 0;
const FourCC actual_format = entry.GetActualFormat();
switch (actual_format) {
case FOURCC_AVC1: {
AVCDecoderConfiguration avc_config;
if (!avc_config.Parse(entry.codec_config_record.data)) {
LOG(ERROR) << "Failed to parse avcc.";
return false; return false;
} }
codec_string = avc_config.GetCodecString();
nalu_length_size = avc_config.length_size();
const std::string codec_string = if (coded_width != avc_config.coded_width() ||
VideoStreamInfo::GetCodecString(kCodecH264, coded_height != avc_config.coded_height()) {
entry.avcc.profile_indication, LOG(WARNING) << "Resolution in VisualSampleEntry (" << coded_width
entry.avcc.profile_compatibility, << "," << coded_height
entry.avcc.avc_level); << ") does not match with resolution in "
uint32_t coded_width = 0;
uint32_t coded_height = 0;
uint32_t pixel_width = 0;
uint32_t pixel_height = 0;
if (entry.avcc.sps_list.empty()) {
LOG(ERROR) << "Cannot find sps in avc decoder configuration record.";
return false;
}
const std::vector<uint8_t>& sps = entry.avcc.sps_list[0];
if (!ExtractResolutionFromSpsData(&sps[0], sps.size(), &coded_width,
&coded_height, &pixel_width,
&pixel_height)) {
LOG(ERROR) << "Failed to parse SPS.";
return false;
}
LOG_IF(WARNING,
entry.width != coded_width || entry.height != coded_height)
<< "Resolution in VisualSampleEntry (" << entry.width << ","
<< entry.height << ") does not match with resolution in "
"AVCDecoderConfigurationRecord (" "AVCDecoderConfigurationRecord ("
<< coded_width << "," << coded_height << avc_config.coded_width() << ","
<< avc_config.coded_height()
<< "). Use AVCDecoderConfigurationRecord."; << "). Use AVCDecoderConfigurationRecord.";
coded_width = avc_config.coded_width();
coded_height = avc_config.coded_height();
}
if (entry.pixel_aspect.h_spacing != 0 || entry.pixel_aspect.v_spacing != 0) { if (pixel_width != avc_config.pixel_width() ||
LOG_IF(WARNING, entry.pixel_aspect.h_spacing != pixel_width || pixel_height != avc_config.pixel_height()) {
entry.pixel_aspect.v_spacing != pixel_height) LOG_IF(WARNING, pixel_width != 1 || pixel_height != 1)
<< "Pixel aspect ratio in PASP box (" << "Pixel aspect ratio in PASP box (" << pixel_width << ","
<< entry.pixel_aspect.h_spacing << "," << pixel_height
<< entry.pixel_aspect.v_spacing << ") does not match with SAR in AVCDecoderConfigurationRecord "
<< ") does not match with SAR in AVCDecoderConfigurationRecord (" "("
<< pixel_width << "," << pixel_height << avc_config.pixel_width() << "," << avc_config.pixel_height()
<< "). Use AVCDecoderConfigurationRecord."; << "). Use AVCDecoderConfigurationRecord.";
pixel_width = avc_config.pixel_width();
pixel_height = avc_config.pixel_height();
}
break;
}
default:
LOG(ERROR) << "Unsupported video format "
<< FourCCToString(actual_format) << " in stsd box.";
return false;
} }
bool is_encrypted = entry.sinf.info.track_encryption.is_encrypted; bool is_encrypted = entry.sinf.info.track_encryption.is_encrypted;
DVLOG(1) << "is_video_track_encrypted_: " << is_encrypted; DVLOG(1) << "is_video_track_encrypted_: " << is_encrypted;
streams.push_back(new VideoStreamInfo(track->header.track_id, streams.push_back(new VideoStreamInfo(
timescale, track->header.track_id, timescale, duration, kCodecH264,
duration, codec_string, track->media.header.language, coded_width, coded_height,
kCodecH264, pixel_width, pixel_height,
codec_string,
track->media.header.language,
coded_width,
coded_height,
pixel_width,
pixel_height,
0, // trick_play_rate 0, // trick_play_rate
entry.avcc.length_size, nalu_length_size, vector_as_array(&entry.codec_config_record.data),
&entry.avcc.data[0], entry.codec_config_record.data.size(), is_encrypted));
entry.avcc.data.size(),
is_encrypted));
} }
} }

View File

@ -179,7 +179,7 @@ void MP4Muxer::GenerateVideoTrak(const VideoStreamInfo* video_info,
video.format = FOURCC_AVC1; video.format = FOURCC_AVC1;
video.width = video_info->width(); video.width = video_info->width();
video.height = video_info->height(); video.height = video_info->height();
video.avcc.data = video_info->extra_data(); video.codec_config_record.data = video_info->extra_data();
if (pixel_width != 1 || pixel_height != 1) { if (pixel_width != 1 || pixel_height != 1) {
video.pixel_aspect.h_spacing = pixel_width; video.pixel_aspect.h_spacing = pixel_width;
video.pixel_aspect.v_spacing = pixel_height; video.pixel_aspect.v_spacing = pixel_height;

View File

@ -109,11 +109,13 @@ scoped_refptr<VideoStreamInfo> WebMVideoClient::GetVideoStreamInfo(
extra_data_size = codec_private.size(); extra_data_size = codec_private.size();
} }
return scoped_refptr<VideoStreamInfo>( // TODO(kqyang): Generate codec string.
new VideoStreamInfo(track_num, kWebMTimeScale, 0, video_codec, std::string codec_string;
VideoStreamInfo::GetCodecString(video_codec, 0, 0, 0),
"", width_after_crop, height_after_crop, sar_x, sar_y, return scoped_refptr<VideoStreamInfo>(new VideoStreamInfo(
0, 0, extra_data, extra_data_size, is_encrypted)); track_num, kWebMTimeScale, 0, video_codec, codec_string, std::string(),
width_after_crop, height_after_crop, sar_x, sar_y, 0, 0, extra_data,
extra_data_size, is_encrypted));
} }
bool WebMVideoClient::OnUInt(int id, int64_t val) { bool WebMVideoClient::OnUInt(int id, int64_t val) {

View File

@ -16,7 +16,7 @@
#include "packager/media/base/media_sample.h" #include "packager/media/base/media_sample.h"
#include "packager/media/base/status.h" #include "packager/media/base/status.h"
#include "packager/media/base/video_stream_info.h" #include "packager/media/base/video_stream_info.h"
#include "packager/media/filters/h264_parser.h" #include "packager/media/filters/avc_decoder_configuration.h"
#include "packager/media/formats/mp2t/adts_header.h" #include "packager/media/formats/mp2t/adts_header.h"
#include "packager/media/formats/mp4/aac_audio_specific_config.h" #include "packager/media/formats/mp4/aac_audio_specific_config.h"
#include "packager/media/formats/mp4/es_descriptor.h" #include "packager/media/formats/mp4/es_descriptor.h"
@ -841,33 +841,24 @@ bool WvmMediaParser::Output(bool output_encrypted_sample) {
stream_config = &stream_infos_[i]->extra_data(); stream_config = &stream_infos_[i]->extra_data();
} }
DCHECK(stream_config); DCHECK(stream_config);
stream_infos_[i]->set_codec_string(VideoStreamInfo::GetCodecString(
kCodecH264, (*stream_config)[1], (*stream_config)[2],
(*stream_config)[3]));
VideoStreamInfo* video_stream_info = VideoStreamInfo* video_stream_info =
reinterpret_cast<VideoStreamInfo*>(stream_infos_[i].get()); reinterpret_cast<VideoStreamInfo*>(stream_infos_[i].get());
uint32_t coded_width = 0; AVCDecoderConfiguration avc_config;
uint32_t coded_height = 0; if (!avc_config.Parse(*stream_config)) {
uint32_t pixel_width = 0;
uint32_t pixel_height = 0;
if (!ExtractResolutionFromDecoderConfig(
vector_as_array(stream_config), stream_config->size(),
&coded_width, &coded_height, &pixel_width, &pixel_height)) {
LOG(WARNING) << "Failed to parse AVCDecoderConfigurationRecord. " LOG(WARNING) << "Failed to parse AVCDecoderConfigurationRecord. "
"Using computed configuration record instead."; "Using computed configuration record instead.";
video_stream_info->set_extra_data(decoder_config_record); video_stream_info->set_extra_data(decoder_config_record);
if (!ExtractResolutionFromDecoderConfig( if (!avc_config.Parse(decoder_config_record)) {
vector_as_array(&decoder_config_record),
decoder_config_record.size(),
&coded_width, &coded_height,
&pixel_width, &pixel_height)) {
LOG(ERROR) << "Failed to parse AVCDecoderConfigurationRecord."; LOG(ERROR) << "Failed to parse AVCDecoderConfigurationRecord.";
return false; return false;
} }
} }
if (pixel_width != video_stream_info->pixel_width() || video_stream_info->set_codec_string(avc_config.GetCodecString());
pixel_height != video_stream_info->pixel_height()) {
if (avc_config.pixel_width() != video_stream_info->pixel_width() ||
avc_config.pixel_height() !=
video_stream_info->pixel_height()) {
LOG_IF(WARNING, video_stream_info->pixel_width() != 0 || LOG_IF(WARNING, video_stream_info->pixel_width() != 0 ||
video_stream_info->pixel_height() != 0) video_stream_info->pixel_height() != 0)
<< "Pixel aspect ratio in WVM metadata (" << "Pixel aspect ratio in WVM metadata ("
@ -875,22 +866,24 @@ bool WvmMediaParser::Output(bool output_encrypted_sample) {
<< video_stream_info->pixel_height() << video_stream_info->pixel_height()
<< ") does not match with SAR in " << ") does not match with SAR in "
"AVCDecoderConfigurationRecord (" "AVCDecoderConfigurationRecord ("
<< pixel_width << "," << pixel_height << avc_config.pixel_width() << ","
<< avc_config.pixel_height()
<< "). Use AVCDecoderConfigurationRecord."; << "). Use AVCDecoderConfigurationRecord.";
video_stream_info->set_pixel_width(pixel_width); video_stream_info->set_pixel_width(avc_config.pixel_width());
video_stream_info->set_pixel_height(pixel_height); video_stream_info->set_pixel_height(avc_config.pixel_height());
} }
if (coded_width != video_stream_info->width() || if (avc_config.coded_width() != video_stream_info->width() ||
coded_height != video_stream_info->height()) { avc_config.coded_height() != video_stream_info->height()) {
LOG(WARNING) << "Resolution in WVM metadata (" LOG(WARNING) << "Resolution in WVM metadata ("
<< video_stream_info->width() << "," << video_stream_info->width() << ","
<< video_stream_info->height() << video_stream_info->height()
<< ") does not match with resolution in " << ") does not match with resolution in "
"AVCDecoderConfigurationRecord (" "AVCDecoderConfigurationRecord ("
<< coded_width << "," << coded_height << avc_config.coded_width() << ","
<< avc_config.coded_height()
<< "). Use AVCDecoderConfigurationRecord."; << "). Use AVCDecoderConfigurationRecord.";
video_stream_info->set_width(coded_width); video_stream_info->set_width(avc_config.coded_width());
video_stream_info->set_height(coded_height); video_stream_info->set_height(avc_config.coded_height());
} }
} }
} }