Move AVCDecoderConfiguration parsing to media/filters
Change-Id: I7daa616e53bdef2206ce145f907b8f55cde87740
This commit is contained in:
parent
3842a5b43c
commit
8fc7f51d81
|
@ -92,25 +92,5 @@ std::string VideoStreamInfo::ToString() const {
|
|||
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 edash_packager
|
||||
|
|
|
@ -28,9 +28,6 @@ enum VideoCodec {
|
|||
class VideoStreamInfo : public StreamInfo {
|
||||
public:
|
||||
/// 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_height is the height of the pixels. 0 if unknown.
|
||||
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_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:
|
||||
~VideoStreamInfo() override;
|
||||
|
||||
|
|
|
@ -41,9 +41,7 @@ VideoStreamInfoParameters GetDefaultVideoStreamInfoParams() {
|
|||
const uint32_t kTimeScale = 10;
|
||||
const uint64_t kVideoStreamDuration = 200;
|
||||
const VideoCodec kH264Codec = kCodecH264;
|
||||
const uint8_t kH264Profile = 1;
|
||||
const uint8_t kH264CompatibleProfile = 1;
|
||||
const uint8_t kH264Level = 1;
|
||||
const char* kCodecString = "avc1.010101";
|
||||
const char* kLanuageUndefined = "und";
|
||||
const uint16_t kWidth = 720;
|
||||
const uint16_t kHeight = 480;
|
||||
|
@ -57,8 +55,7 @@ VideoStreamInfoParameters GetDefaultVideoStreamInfoParams() {
|
|||
params.time_scale = kTimeScale;
|
||||
params.duration = kVideoStreamDuration;
|
||||
params.codec = kH264Codec;
|
||||
params.codec_string = VideoStreamInfo::GetCodecString(
|
||||
kCodecH264, kH264Profile, kH264CompatibleProfile, kH264Level);
|
||||
params.codec_string = kCodecString;
|
||||
params.language = kLanuageUndefined;
|
||||
params.width = kWidth;
|
||||
params.height = kHeight;
|
||||
|
|
|
@ -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
|
|
@ -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_
|
|
@ -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
|
|
@ -13,6 +13,8 @@
|
|||
'target_name': 'filters',
|
||||
'type': '<(component)',
|
||||
'sources': [
|
||||
'avc_decoder_configuration.cc',
|
||||
'avc_decoder_configuration.h',
|
||||
'h264_bit_reader.cc',
|
||||
'h264_bit_reader.h',
|
||||
'h264_byte_to_unit_stream_converter.cc',
|
||||
|
@ -28,6 +30,7 @@
|
|||
'target_name': 'filters_unittest',
|
||||
'type': '<(gtest_target_type)',
|
||||
'sources': [
|
||||
'avc_decoder_configuration_unittest.cc',
|
||||
'h264_bit_reader_unittest.cc',
|
||||
'h264_byte_to_unit_stream_converter_unittest.cc',
|
||||
'h264_parser_unittest.cc',
|
||||
|
|
|
@ -12,62 +12,6 @@
|
|||
namespace edash_packager {
|
||||
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
|
||||
// RBSP semantics.
|
||||
bool ExtractResolutionFromSps(const H264SPS& sps,
|
||||
|
@ -133,8 +77,6 @@ bool ExtractResolutionFromSps(const H264SPS& sps,
|
|||
return true;
|
||||
}
|
||||
|
||||
#undef RCHECK
|
||||
|
||||
bool H264SliceHeader::IsPSlice() const {
|
||||
return (slice_type % 5 == kPSlice);
|
||||
}
|
||||
|
|
|
@ -17,28 +17,9 @@
|
|||
namespace edash_packager {
|
||||
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
|
||||
// cropping; |pixel_width:pixel_height| contains pixel aspect ratio, 1:1 is
|
||||
// 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;
|
||||
bool ExtractResolutionFromSps(const H264SPS& sps,
|
||||
uint32_t* coded_width,
|
||||
|
|
|
@ -65,39 +65,24 @@ 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) {
|
||||
const uint8_t kSps[] = {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};
|
||||
|
||||
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_height = 0;
|
||||
uint32_t pixel_width = 0;
|
||||
uint32_t pixel_height = 0;
|
||||
ASSERT_TRUE(ExtractResolutionFromSpsData(kSps, arraysize(kSps), &coded_width,
|
||||
&coded_height, &pixel_width,
|
||||
&pixel_height));
|
||||
ASSERT_TRUE(ExtractResolutionFromSps(*parser.GetSPS(sps_id), &coded_width,
|
||||
&coded_height, &pixel_width,
|
||||
&pixel_height));
|
||||
EXPECT_EQ(720u, coded_width);
|
||||
EXPECT_EQ(360u, coded_height);
|
||||
EXPECT_EQ(8u, pixel_width);
|
||||
|
@ -110,13 +95,18 @@ TEST(H264ParserTest, ExtractResolutionFromSpsDataWithCropping) {
|
|||
0x9F, 0x01, 0x10, 0x00, 0x00, 0x03, 0x00, 0x10, 0x00,
|
||||
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_height = 0;
|
||||
uint32_t pixel_width = 0;
|
||||
uint32_t pixel_height = 0;
|
||||
ASSERT_TRUE(ExtractResolutionFromSpsData(kSps, arraysize(kSps), &coded_width,
|
||||
&coded_height, &pixel_width,
|
||||
&pixel_height));
|
||||
ASSERT_TRUE(ExtractResolutionFromSps(*parser.GetSPS(sps_id), &coded_width,
|
||||
&coded_height, &pixel_width,
|
||||
&pixel_height));
|
||||
EXPECT_EQ(320u, coded_width);
|
||||
EXPECT_EQ(180u, coded_height);
|
||||
EXPECT_EQ(1u, pixel_width);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "packager/media/base/offset_byte_queue.h"
|
||||
#include "packager/media/base/timestamp.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_parser.h"
|
||||
#include "packager/media/formats/mp2t/mp2t_common.h"
|
||||
|
@ -361,10 +362,9 @@ bool EsParserH264::UpdateVideoDecoderConfig(const H264SPS* sps) {
|
|||
kMpeg2Timescale,
|
||||
kInfiniteDuration,
|
||||
kCodecH264,
|
||||
VideoStreamInfo::GetCodecString(kCodecH264,
|
||||
decoder_config_record[1],
|
||||
decoder_config_record[2],
|
||||
decoder_config_record[3]),
|
||||
AVCDecoderConfiguration::GetCodecString(decoder_config_record[1],
|
||||
decoder_config_record[2],
|
||||
decoder_config_record[3]),
|
||||
std::string(),
|
||||
coded_width,
|
||||
coded_height,
|
||||
|
|
|
@ -35,6 +35,8 @@ const uint32_t kVideoResolution = 0x00480000; // 72 dpi.
|
|||
const uint16_t kVideoFrameCount = 1;
|
||||
const uint16_t kVideoDepth = 0x0018;
|
||||
|
||||
const uint32_t kCompressorNameSize = 32u;
|
||||
|
||||
// Utility functions to check if the 64bit integers can fit in 32bit integer.
|
||||
bool IsFitIn32Bits(uint64_t a) {
|
||||
return a <= std::numeric_limits<uint32_t>::max();
|
||||
|
@ -873,63 +875,25 @@ uint32_t HandlerReference::ComputeSize() {
|
|||
return atom_size;
|
||||
}
|
||||
|
||||
AVCDecoderConfigurationRecord::AVCDecoderConfigurationRecord()
|
||||
: version(0),
|
||||
profile_indication(0),
|
||||
profile_compatibility(0),
|
||||
avc_level(0),
|
||||
length_size(0) {}
|
||||
CodecConfigurationRecord::CodecConfigurationRecord() : box_type(FOURCC_NULL) {}
|
||||
CodecConfigurationRecord::~CodecConfigurationRecord() {}
|
||||
FourCC CodecConfigurationRecord::BoxType() const {
|
||||
// CodecConfigurationRecord should be parsed according to format recovered in
|
||||
// VideoSampleEntry. |box_type| is determined dynamically there.
|
||||
return box_type;
|
||||
}
|
||||
|
||||
AVCDecoderConfigurationRecord::~AVCDecoderConfigurationRecord() {}
|
||||
FourCC AVCDecoderConfigurationRecord::BoxType() const { return FOURCC_AVCC; }
|
||||
|
||||
bool AVCDecoderConfigurationRecord::ReadWrite(BoxBuffer* buffer) {
|
||||
bool CodecConfigurationRecord::ReadWrite(BoxBuffer* buffer) {
|
||||
RCHECK(Box::ReadWrite(buffer));
|
||||
if (buffer->Reading()) {
|
||||
RCHECK(buffer->ReadWriteVector(&data, buffer->Size() - buffer->Pos()));
|
||||
BufferReader buffer_reader(&data[0], data.size());
|
||||
return ParseData(&buffer_reader);
|
||||
} else {
|
||||
RCHECK(buffer->ReadWriteVector(&data, data.size()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AVCDecoderConfigurationRecord::ParseData(BufferReader* reader) {
|
||||
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() {
|
||||
uint32_t CodecConfigurationRecord::ComputeSize() {
|
||||
atom_size = 0;
|
||||
if (!data.empty())
|
||||
atom_size = kBoxSize + data.size();
|
||||
|
@ -1009,10 +973,16 @@ bool VideoSampleEntry::ReadWrite(BoxBuffer* buffer) {
|
|||
}
|
||||
}
|
||||
|
||||
if (format == FOURCC_AVC1 ||
|
||||
(format == FOURCC_ENCV && sinf.format.format == FOURCC_AVC1)) {
|
||||
RCHECK(buffer->ReadWriteChild(&avcc));
|
||||
const FourCC actual_format = GetActualFormat();
|
||||
switch (actual_format) {
|
||||
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));
|
||||
return true;
|
||||
}
|
||||
|
@ -1022,7 +992,7 @@ uint32_t VideoSampleEntry::ComputeSize() {
|
|||
sizeof(height) + sizeof(kVideoResolution) * 2 +
|
||||
sizeof(kVideoFrameCount) + sizeof(kVideoDepth) +
|
||||
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.
|
||||
return atom_size;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#ifndef MEDIA_FORMATS_MP4_BOX_DEFINITIONS_H_
|
||||
#define MEDIA_FORMATS_MP4_BOX_DEFINITIONS_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "packager/media/formats/mp4/aac_audio_specific_config.h"
|
||||
|
@ -165,27 +164,12 @@ struct HandlerReference : FullBox {
|
|||
TrackType type;
|
||||
};
|
||||
|
||||
struct AVCDecoderConfigurationRecord : Box {
|
||||
DECLARE_BOX_METHODS(AVCDecoderConfigurationRecord);
|
||||
bool ParseData(BufferReader* reader);
|
||||
struct CodecConfigurationRecord : Box {
|
||||
DECLARE_BOX_METHODS(CodecConfigurationRecord);
|
||||
|
||||
// Contains full avc decoder configuration record as defined in iso14496-15
|
||||
// 5.2.4.1, including possible extension bytes described in paragraph 3.
|
||||
// Known fields defined in the spec are also parsed and included in this
|
||||
// structure.
|
||||
FourCC box_type;
|
||||
// Contains full codec configuration record, including possible extension boxes.
|
||||
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 {
|
||||
|
@ -197,6 +181,10 @@ struct PixelAspectRatioBox : Box {
|
|||
|
||||
struct VideoSampleEntry : Box {
|
||||
DECLARE_BOX_METHODS(VideoSampleEntry);
|
||||
// Returns actual format of this sample entry.
|
||||
FourCC GetActualFormat() const {
|
||||
return format == FOURCC_ENCV ? sinf.format.format : format;
|
||||
}
|
||||
|
||||
FourCC format;
|
||||
uint16_t data_reference_index;
|
||||
|
@ -205,9 +193,7 @@ struct VideoSampleEntry : Box {
|
|||
|
||||
PixelAspectRatioBox pixel_aspect;
|
||||
ProtectionSchemeInfo sinf;
|
||||
|
||||
// Currently expected to be present regardless of format.
|
||||
AVCDecoderConfigurationRecord avcc;
|
||||
CodecConfigurationRecord codec_config_record;
|
||||
};
|
||||
|
||||
struct ElementaryStreamDescriptor : FullBox {
|
||||
|
@ -219,6 +205,10 @@ struct ElementaryStreamDescriptor : FullBox {
|
|||
|
||||
struct AudioSampleEntry : Box {
|
||||
DECLARE_BOX_METHODS(AudioSampleEntry);
|
||||
// Returns actual format of this sample entry.
|
||||
FourCC GetActualFormat() const {
|
||||
return format == FOURCC_ENCA ? sinf.format.format : format;
|
||||
}
|
||||
|
||||
FourCC format;
|
||||
uint16_t data_reference_index;
|
||||
|
|
|
@ -165,8 +165,8 @@ inline bool operator==(const HandlerReference& lhs,
|
|||
return lhs.type == rhs.type;
|
||||
}
|
||||
|
||||
inline bool operator==(const AVCDecoderConfigurationRecord& lhs,
|
||||
const AVCDecoderConfigurationRecord& rhs) {
|
||||
inline bool operator==(const CodecConfigurationRecord& lhs,
|
||||
const CodecConfigurationRecord& rhs) {
|
||||
return lhs.data == rhs.data;
|
||||
}
|
||||
|
||||
|
@ -181,7 +181,7 @@ inline bool operator==(const VideoSampleEntry& lhs,
|
|||
lhs.data_reference_index == rhs.data_reference_index &&
|
||||
lhs.width == rhs.width && lhs.height == rhs.height &&
|
||||
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) {
|
||||
|
|
|
@ -274,26 +274,24 @@ class BoxDefinitionsTestGeneral : public testing::Test {
|
|||
|
||||
void Modify(PixelAspectRatioBox* pasp) { pasp->v_spacing *= 8; }
|
||||
|
||||
void Fill(AVCDecoderConfigurationRecord* avcc) {
|
||||
void Fill(CodecConfigurationRecord* codec_config_record) {
|
||||
const uint8_t kAvccData[] = {
|
||||
0x01, 0x64, 0x00, 0x1f, 0xff, 0xe1, 0x00, 0x18, 0x67, 0x64, 0x00,
|
||||
0x1f, 0xac, 0xd9, 0x40, 0x50, 0x05, 0xbb, 0x01, 0x10, 0x00, 0x00,
|
||||
0x3e, 0x90, 0x00, 0x0e, 0xa6, 0x00, 0xf1, 0x83, 0x19, 0x60, 0x01,
|
||||
0x00, 0x06, 0x68, 0xeb, 0xe3, 0xcb, 0x22, 0xc0};
|
||||
BufferReader buffer_reader(kAvccData, arraysize(kAvccData));
|
||||
CHECK(avcc->ParseData(&buffer_reader));
|
||||
avcc->data.assign(kAvccData, kAvccData + arraysize(kAvccData));
|
||||
codec_config_record->data.assign(kAvccData,
|
||||
kAvccData + arraysize(kAvccData));
|
||||
}
|
||||
|
||||
void Modify(AVCDecoderConfigurationRecord* avcc) {
|
||||
void Modify(CodecConfigurationRecord* codec_config_record) {
|
||||
const uint8_t kAvccData[] = {
|
||||
0x01, 0x64, 0x00, 0x1e, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00,
|
||||
0x1e, 0xac, 0xd9, 0x40, 0xa0, 0x2f, 0xf9, 0x70, 0x11, 0x00, 0x00,
|
||||
0x03, 0x03, 0xe9, 0x00, 0x00, 0xea, 0x60, 0x0f, 0x16, 0x2d, 0x96,
|
||||
0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
|
||||
BufferReader buffer_reader(kAvccData, arraysize(kAvccData));
|
||||
CHECK(avcc->ParseData(&buffer_reader));
|
||||
avcc->data.assign(kAvccData, kAvccData + arraysize(kAvccData));
|
||||
codec_config_record->data.assign(kAvccData,
|
||||
kAvccData + arraysize(kAvccData));
|
||||
}
|
||||
|
||||
void Fill(VideoSampleEntry* encv) {
|
||||
|
@ -303,12 +301,12 @@ class BoxDefinitionsTestGeneral : public testing::Test {
|
|||
encv->height = 600;
|
||||
Fill(&encv->pixel_aspect);
|
||||
Fill(&encv->sinf);
|
||||
Fill(&encv->avcc);
|
||||
Fill(&encv->codec_config_record);
|
||||
}
|
||||
|
||||
void Modify(VideoSampleEntry* encv) {
|
||||
encv->height += 600;
|
||||
Modify(&encv->avcc);
|
||||
Modify(&encv->codec_config_record);
|
||||
}
|
||||
|
||||
void Fill(ElementaryStreamDescriptor* esds) {
|
||||
|
@ -725,7 +723,7 @@ class BoxDefinitionsTestGeneral : public testing::Test {
|
|||
bool IsOptional(const ProtectionSchemeInfo* box) { return true; }
|
||||
bool IsOptional(const EditList* 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 ElementaryStreamDescriptor* box) { return true; }
|
||||
bool IsOptional(const CompositionTimeToSample* box) { return true; }
|
||||
|
@ -755,7 +753,7 @@ typedef testing::Types<
|
|||
EditList,
|
||||
Edit,
|
||||
HandlerReference,
|
||||
AVCDecoderConfigurationRecord,
|
||||
CodecConfigurationRecord,
|
||||
PixelAspectRatioBox,
|
||||
VideoSampleEntry,
|
||||
ElementaryStreamDescriptor,
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "packager/media/base/video_stream_info.h"
|
||||
#include "packager/media/file/file.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_reader.h"
|
||||
#include "packager/media/formats/mp4/es_descriptor.h"
|
||||
|
@ -355,73 +355,70 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
|
|||
desc_idx = 0;
|
||||
const VideoSampleEntry& entry = samp_descr.video_entries[desc_idx];
|
||||
|
||||
if (!(entry.format == FOURCC_AVC1 ||
|
||||
(entry.format == FOURCC_ENCV &&
|
||||
entry.sinf.format.format == FOURCC_AVC1))) {
|
||||
LOG(ERROR) << "Unsupported video format 0x"
|
||||
<< std::hex << entry.format << " in stsd box.";
|
||||
return false;
|
||||
uint32_t coded_width = entry.width;
|
||||
uint32_t coded_height = entry.height;
|
||||
uint32_t pixel_width = entry.pixel_aspect.h_spacing;
|
||||
uint32_t pixel_height = entry.pixel_aspect.v_spacing;
|
||||
if (pixel_width == 0 && pixel_height == 0) {
|
||||
pixel_width = 1;
|
||||
pixel_height = 1;
|
||||
}
|
||||
std::string codec_string;
|
||||
uint8_t nalu_length_size = 0;
|
||||
|
||||
const std::string codec_string =
|
||||
VideoStreamInfo::GetCodecString(kCodecH264,
|
||||
entry.avcc.profile_indication,
|
||||
entry.avcc.profile_compatibility,
|
||||
entry.avcc.avc_level);
|
||||
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;
|
||||
}
|
||||
codec_string = avc_config.GetCodecString();
|
||||
nalu_length_size = avc_config.length_size();
|
||||
|
||||
uint32_t coded_width = 0;
|
||||
uint32_t coded_height = 0;
|
||||
uint32_t pixel_width = 0;
|
||||
uint32_t pixel_height = 0;
|
||||
if (coded_width != avc_config.coded_width() ||
|
||||
coded_height != avc_config.coded_height()) {
|
||||
LOG(WARNING) << "Resolution in VisualSampleEntry (" << coded_width
|
||||
<< "," << coded_height
|
||||
<< ") does not match with resolution in "
|
||||
"AVCDecoderConfigurationRecord ("
|
||||
<< avc_config.coded_width() << ","
|
||||
<< avc_config.coded_height()
|
||||
<< "). Use AVCDecoderConfigurationRecord.";
|
||||
coded_width = avc_config.coded_width();
|
||||
coded_height = avc_config.coded_height();
|
||||
}
|
||||
|
||||
if (entry.avcc.sps_list.empty()) {
|
||||
LOG(ERROR) << "Cannot find sps in avc decoder configuration record.";
|
||||
if (pixel_width != avc_config.pixel_width() ||
|
||||
pixel_height != avc_config.pixel_height()) {
|
||||
LOG_IF(WARNING, pixel_width != 1 || pixel_height != 1)
|
||||
<< "Pixel aspect ratio in PASP box (" << pixel_width << ","
|
||||
<< pixel_height
|
||||
<< ") does not match with SAR in AVCDecoderConfigurationRecord "
|
||||
"("
|
||||
<< avc_config.pixel_width() << "," << avc_config.pixel_height()
|
||||
<< "). 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;
|
||||
}
|
||||
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 ("
|
||||
<< coded_width << "," << coded_height
|
||||
<< "). Use AVCDecoderConfigurationRecord.";
|
||||
|
||||
if (entry.pixel_aspect.h_spacing != 0 || entry.pixel_aspect.v_spacing != 0) {
|
||||
LOG_IF(WARNING, entry.pixel_aspect.h_spacing != pixel_width ||
|
||||
entry.pixel_aspect.v_spacing != pixel_height)
|
||||
<< "Pixel aspect ratio in PASP box ("
|
||||
<< entry.pixel_aspect.h_spacing << ","
|
||||
<< entry.pixel_aspect.v_spacing
|
||||
<< ") does not match with SAR in AVCDecoderConfigurationRecord ("
|
||||
<< pixel_width << "," << pixel_height
|
||||
<< "). Use AVCDecoderConfigurationRecord.";
|
||||
}
|
||||
|
||||
bool is_encrypted = entry.sinf.info.track_encryption.is_encrypted;
|
||||
DVLOG(1) << "is_video_track_encrypted_: " << is_encrypted;
|
||||
streams.push_back(new VideoStreamInfo(track->header.track_id,
|
||||
timescale,
|
||||
duration,
|
||||
kCodecH264,
|
||||
codec_string,
|
||||
track->media.header.language,
|
||||
coded_width,
|
||||
coded_height,
|
||||
pixel_width,
|
||||
pixel_height,
|
||||
0, // trick_play_rate
|
||||
entry.avcc.length_size,
|
||||
&entry.avcc.data[0],
|
||||
entry.avcc.data.size(),
|
||||
is_encrypted));
|
||||
streams.push_back(new VideoStreamInfo(
|
||||
track->header.track_id, timescale, duration, kCodecH264,
|
||||
codec_string, track->media.header.language, coded_width, coded_height,
|
||||
pixel_width, pixel_height,
|
||||
0, // trick_play_rate
|
||||
nalu_length_size, vector_as_array(&entry.codec_config_record.data),
|
||||
entry.codec_config_record.data.size(), is_encrypted));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -179,7 +179,7 @@ void MP4Muxer::GenerateVideoTrak(const VideoStreamInfo* video_info,
|
|||
video.format = FOURCC_AVC1;
|
||||
video.width = video_info->width();
|
||||
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) {
|
||||
video.pixel_aspect.h_spacing = pixel_width;
|
||||
video.pixel_aspect.v_spacing = pixel_height;
|
||||
|
|
|
@ -109,11 +109,13 @@ scoped_refptr<VideoStreamInfo> WebMVideoClient::GetVideoStreamInfo(
|
|||
extra_data_size = codec_private.size();
|
||||
}
|
||||
|
||||
return scoped_refptr<VideoStreamInfo>(
|
||||
new VideoStreamInfo(track_num, kWebMTimeScale, 0, video_codec,
|
||||
VideoStreamInfo::GetCodecString(video_codec, 0, 0, 0),
|
||||
"", width_after_crop, height_after_crop, sar_x, sar_y,
|
||||
0, 0, extra_data, extra_data_size, is_encrypted));
|
||||
// TODO(kqyang): Generate codec string.
|
||||
std::string codec_string;
|
||||
|
||||
return scoped_refptr<VideoStreamInfo>(new VideoStreamInfo(
|
||||
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) {
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "packager/media/base/media_sample.h"
|
||||
#include "packager/media/base/status.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/mp4/aac_audio_specific_config.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();
|
||||
}
|
||||
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 =
|
||||
reinterpret_cast<VideoStreamInfo*>(stream_infos_[i].get());
|
||||
uint32_t coded_width = 0;
|
||||
uint32_t coded_height = 0;
|
||||
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)) {
|
||||
AVCDecoderConfiguration avc_config;
|
||||
if (!avc_config.Parse(*stream_config)) {
|
||||
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);
|
||||
if (!ExtractResolutionFromDecoderConfig(
|
||||
vector_as_array(&decoder_config_record),
|
||||
decoder_config_record.size(),
|
||||
&coded_width, &coded_height,
|
||||
&pixel_width, &pixel_height)) {
|
||||
if (!avc_config.Parse(decoder_config_record)) {
|
||||
LOG(ERROR) << "Failed to parse AVCDecoderConfigurationRecord.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (pixel_width != video_stream_info->pixel_width() ||
|
||||
pixel_height != video_stream_info->pixel_height()) {
|
||||
video_stream_info->set_codec_string(avc_config.GetCodecString());
|
||||
|
||||
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 ||
|
||||
video_stream_info->pixel_height() != 0)
|
||||
<< "Pixel aspect ratio in WVM metadata ("
|
||||
|
@ -875,22 +866,24 @@ bool WvmMediaParser::Output(bool output_encrypted_sample) {
|
|||
<< video_stream_info->pixel_height()
|
||||
<< ") does not match with SAR in "
|
||||
"AVCDecoderConfigurationRecord ("
|
||||
<< pixel_width << "," << pixel_height
|
||||
<< avc_config.pixel_width() << ","
|
||||
<< avc_config.pixel_height()
|
||||
<< "). Use AVCDecoderConfigurationRecord.";
|
||||
video_stream_info->set_pixel_width(pixel_width);
|
||||
video_stream_info->set_pixel_height(pixel_height);
|
||||
video_stream_info->set_pixel_width(avc_config.pixel_width());
|
||||
video_stream_info->set_pixel_height(avc_config.pixel_height());
|
||||
}
|
||||
if (coded_width != video_stream_info->width() ||
|
||||
coded_height != video_stream_info->height()) {
|
||||
if (avc_config.coded_width() != video_stream_info->width() ||
|
||||
avc_config.coded_height() != video_stream_info->height()) {
|
||||
LOG(WARNING) << "Resolution in WVM metadata ("
|
||||
<< video_stream_info->width() << ","
|
||||
<< video_stream_info->height()
|
||||
<< ") does not match with resolution in "
|
||||
"AVCDecoderConfigurationRecord ("
|
||||
<< coded_width << "," << coded_height
|
||||
<< avc_config.coded_width() << ","
|
||||
<< avc_config.coded_height()
|
||||
<< "). Use AVCDecoderConfigurationRecord.";
|
||||
video_stream_info->set_width(coded_width);
|
||||
video_stream_info->set_height(coded_height);
|
||||
video_stream_info->set_width(avc_config.coded_width());
|
||||
video_stream_info->set_height(avc_config.coded_height());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue