Fix bug in VPx codec configuration.

Before, we converted the WebM configuration to MP4 in the video
client, however this lead to a bug when fields were missing.  So
now don't convert until the cluster parser so the extra info from
the stream can be added.

This also fixes a bug where the value was not printed in the warning
logs.

b/29580732

Change-Id: If0a1a4d135f98292cdaae15a11027f42d844e85d
This commit is contained in:
Jacob Trimble 2016-06-22 17:03:53 -07:00
parent f27960e00d
commit f9bf197f2b
3 changed files with 63 additions and 85 deletions

View File

@ -38,6 +38,23 @@ std::string VPCodecAsString(VideoCodec codec) {
}
}
template <typename T>
void MergeField(const std::string& name,
T source_value,
bool source_is_set,
T* dest_value,
bool* dest_is_set) {
if (!*dest_is_set || source_is_set) {
if (*dest_is_set && source_value != *dest_value) {
LOG(WARNING) << "VPx " << name << " is inconsistent, "
<< static_cast<uint32_t>(*dest_value) << " vs "
<< static_cast<uint32_t>(source_value);
}
*dest_value = source_value;
*dest_is_set = true;
}
}
} // namespace
VPCodecConfigurationRecord::VPCodecConfigurationRecord() {}
@ -153,29 +170,36 @@ void VPCodecConfigurationRecord::WriteMP4(std::vector<uint8_t>* data) const {
void VPCodecConfigurationRecord::WriteWebM(std::vector<uint8_t>* data) const {
BufferWriter writer;
writer.AppendInt(static_cast<uint8_t>(kFeatureProfile)); // ID = 1
writer.AppendInt(static_cast<uint8_t>(1)); // Length = 1
writer.AppendInt(static_cast<uint8_t>(profile_));
if (profile_is_set_) {
writer.AppendInt(static_cast<uint8_t>(kFeatureProfile)); // ID = 1
writer.AppendInt(static_cast<uint8_t>(1)); // Length = 1
writer.AppendInt(static_cast<uint8_t>(profile_));
}
if (level_ != 0) {
if (level_is_set_ && level_ != 0) {
writer.AppendInt(static_cast<uint8_t>(kFeatureLevel)); // ID = 2
writer.AppendInt(static_cast<uint8_t>(1)); // Length = 1
writer.AppendInt(static_cast<uint8_t>(level_));
}
writer.AppendInt(static_cast<uint8_t>(kFeatureBitDepth)); // ID = 3
writer.AppendInt(static_cast<uint8_t>(1)); // Length = 1
writer.AppendInt(static_cast<uint8_t>(bit_depth_));
if (bit_depth_is_set_) {
writer.AppendInt(static_cast<uint8_t>(kFeatureBitDepth)); // ID = 3
writer.AppendInt(static_cast<uint8_t>(1)); // Length = 1
writer.AppendInt(static_cast<uint8_t>(bit_depth_));
}
// WebM doesn't differentiate whether it is vertical or collocated with luma
// for 4:2:0.
const uint8_t subsampling =
chroma_subsampling_ == CHROMA_420_COLLOCATED_WITH_LUMA
? CHROMA_420_VERTICAL
: chroma_subsampling_;
writer.AppendInt(static_cast<uint8_t>(kFeatureChromaSubsampling)); // ID = 4
writer.AppendInt(static_cast<uint8_t>(1)); // Length = 1
writer.AppendInt(subsampling);
if (chroma_subsampling_is_set_) {
// WebM doesn't differentiate whether it is vertical or collocated with luma
// for 4:2:0.
const uint8_t subsampling =
chroma_subsampling_ == CHROMA_420_COLLOCATED_WITH_LUMA
? CHROMA_420_VERTICAL
: chroma_subsampling_;
// ID = 4, Length = 1
writer.AppendInt(static_cast<uint8_t>(kFeatureChromaSubsampling));
writer.AppendInt(static_cast<uint8_t>(1));
writer.AppendInt(subsampling);
}
writer.SwapBuffer(data);
}
@ -203,64 +227,24 @@ std::string VPCodecConfigurationRecord::GetCodecString(VideoCodec codec) const {
void VPCodecConfigurationRecord::MergeFrom(
const VPCodecConfigurationRecord& other) {
if (!profile_is_set_ || other.profile_is_set_) {
profile_ = other.profile();
profile_is_set_ = true;
}
if (!level_is_set_ || other.level_is_set_) {
if (level_is_set_ && other.level() != level_) {
LOG(WARNING) << "VPx level is inconsistent, " << level_ << " vs "
<< other.level();
}
level_ = other.level();
level_is_set_ = true;
}
if (!bit_depth_is_set_ || other.bit_depth_is_set_) {
if (bit_depth_is_set_ && bit_depth_ != other.bit_depth()) {
LOG(WARNING) << "VPx bit depth is inconsistent, " << bit_depth_ << " vs "
<< other.bit_depth();
}
bit_depth_ = other.bit_depth();
bit_depth_is_set_ = true;
}
if (!color_space_is_set_ || other.color_space_is_set_) {
if (color_space_is_set_ && color_space_ != other.color_space()) {
LOG(WARNING) << "VPx color space is inconsistent, " << color_space_
<< " vs " << other.color_space();
}
color_space_ = other.color_space();
color_space_is_set_ = true;
}
if (!chroma_subsampling_is_set_ || other.chroma_subsampling_is_set_) {
if (chroma_subsampling_is_set_ &&
chroma_subsampling_ != other.chroma_subsampling_) {
LOG(WARNING) << "VPx chroma subsampling is inconsistent, "
<< chroma_subsampling_ << " vs "
<< other.chroma_subsampling();
}
chroma_subsampling_ = other.chroma_subsampling();
chroma_subsampling_is_set_ = true;
}
if (!transfer_function_is_set_ || other.transfer_function_is_set_) {
if (transfer_function_is_set_ &&
transfer_function_ != other.transfer_function_) {
LOG(WARNING) << "VPx transfer function is inconsistent, "
<< transfer_function_ << " vs "
<< other.transfer_function();
}
transfer_function_ = other.transfer_function();
transfer_function_is_set_ = true;
}
if (!video_full_range_flag_is_set_ || other.video_full_range_flag_is_set_) {
if (video_full_range_flag_is_set_ &&
video_full_range_flag_ != other.video_full_range_flag_) {
LOG(WARNING) << "VPx video full-range flag is inconsistent, "
<< video_full_range_flag_<< " vs "
<< other.video_full_range_flag();
}
video_full_range_flag_ = other.video_full_range_flag();
video_full_range_flag_is_set_ = true;
}
MergeField("profile", other.profile_, other.profile_is_set_, &profile_,
&profile_is_set_);
MergeField("level", other.level_, other.level_is_set_, &level_,
&level_is_set_);
MergeField("bit depth", other.bit_depth_, other.bit_depth_is_set_,
&bit_depth_, &bit_depth_is_set_);
MergeField("color space", other.color_space_, other.color_space_is_set_,
&color_space_, &color_space_is_set_);
MergeField("chroma subsampling", other.chroma_subsampling_,
other.chroma_subsampling_is_set_, &chroma_subsampling_,
&chroma_subsampling_is_set_);
MergeField("transfer function", other.transfer_function_,
other.transfer_function_is_set_, &transfer_function_,
&transfer_function_is_set_);
MergeField("video full range flag", other.video_full_range_flag_,
other.video_full_range_flag_is_set_, &video_full_range_flag_,
&video_full_range_flag_is_set_);
if (codec_initialization_data_.empty() ||
!other.codec_initialization_data_.empty()) {
if (!codec_initialization_data_.empty() &&

View File

@ -458,7 +458,7 @@ bool WebMClusterParser::OnBlock(bool is_simple_block,
VPCodecConfigurationRecord codec_config;
if (!video_stream_info_->codec_config().empty())
codec_config.ParseMP4(video_stream_info_->codec_config());
codec_config.ParseWebM(video_stream_info_->codec_config());
codec_config.MergeFrom(vpx_parser->codec_config());
video_stream_info_->set_codec_string(

View File

@ -51,22 +51,16 @@ void WebMVideoClient::Reset() {
scoped_refptr<VideoStreamInfo> WebMVideoClient::GetVideoStreamInfo(
int64_t track_num,
const std::string& codec_id,
const std::vector<uint8_t>& codec_private_in,
const std::vector<uint8_t>& codec_private,
bool is_encrypted) {
std::vector<uint8_t> codec_private = codec_private_in;
VideoCodec video_codec = kUnknownVideoCodec;
if (codec_id == "V_VP8") {
video_codec = kCodecVP8;
} else if (codec_id == "V_VP9") {
video_codec = kCodecVP9;
// Need to parse and convert the codec private data to MP4 format.
VPCodecConfigurationRecord vp_config;
if (!vp_config.ParseWebM(codec_private)) {
LOG(ERROR) << "Unable to parse VP9 codec configuration";
return scoped_refptr<VideoStreamInfo>();
}
vp_config.WriteMP4(&codec_private);
// The codec private data is in WebM format, but needs to be converted to
// MP4 format. Don't do it yet, it will be handled in
// webm_cluster_parser.cc
} else if (codec_id == "V_VP10") {
video_codec = kCodecVP10;
} else {