From 2a95367dd4ad885e52be0321e74e967e0bebab3b Mon Sep 17 00:00:00 2001 From: Kongqun Yang Date: Thu, 20 Aug 2015 12:06:02 -0700 Subject: [PATCH] Move SAR extraction out of video_stream_info.cc This fixes a circular dependency of media_base depends on filter and filter depends on media_base. Also added code to extract sar in WvmMediaParser if it is not yet extracted when setting extra_data. Change-Id: I1b5aef2444e4134c9b6663911ac5e5c4c220404a --- packager/media/base/media_base.gyp | 1 - packager/media/base/video_stream_info.cc | 18 +----------- packager/media/base/video_stream_info.h | 3 ++ packager/media/file/io_cache.cc | 2 +- packager/media/filters/h264_parser.cc | 27 +++++++++++------ packager/media/filters/h264_parser.h | 15 ++++++++-- .../media/filters/h264_parser_unittest.cc | 29 ++++++++++++++++++- .../media/formats/mp4/mp4_media_parser.cc | 14 +++++++-- packager/media/formats/mp4/mp4_muxer.cc | 16 ++++++---- .../media/formats/wvm/wvm_media_parser.cc | 13 +++++++++ 10 files changed, 99 insertions(+), 39 deletions(-) diff --git a/packager/media/base/media_base.gyp b/packager/media/base/media_base.gyp index 1464407a0c..36ea032ea1 100644 --- a/packager/media/base/media_base.gyp +++ b/packager/media/base/media_base.gyp @@ -78,7 +78,6 @@ '../../base/base.gyp:base', '../../third_party/curl/curl.gyp:libcurl', '../../third_party/openssl/openssl.gyp:openssl', - '../filters/filters.gyp:filters', ], }, { diff --git a/packager/media/base/video_stream_info.cc b/packager/media/base/video_stream_info.cc index f3c7ed942a..99f0704a0f 100644 --- a/packager/media/base/video_stream_info.cc +++ b/packager/media/base/video_stream_info.cc @@ -6,13 +6,12 @@ #include "packager/media/base/video_stream_info.h" -#include "base/logging.h" +#include "packager/base/logging.h" #include "packager/base/stl_util.h" #include "packager/base/strings/string_number_conversions.h" #include "packager/base/strings/string_util.h" #include "packager/base/strings/stringprintf.h" #include "packager/media/base/limits.h" -#include "packager/media/filters/h264_parser.h" namespace edash_packager { namespace media { @@ -73,21 +72,6 @@ VideoStreamInfo::VideoStreamInfo(int track_id, pixel_height_(pixel_height), trick_play_rate_(trick_play_rate), nalu_length_size_(nalu_length_size) { - // If H264 and the pixel width and height were not passed in, parse the extra - // data to get the sar width and height. - if ((pixel_width_ == 0 || pixel_height_ == 0) && - codec == kCodecH264 && - extra_data && extra_data_size > 0) { - ExtractSarFromDecoderConfig(extra_data, extra_data_size, &pixel_width_, - &pixel_height_); - DVLOG_IF(2, pixel_width_ == 0 || pixel_height_ == 0) - << "Failed to extract sar_width and sar_height."; - } - if (pixel_width_ == 0 || pixel_height_ == 0) { - LOG(WARNING) << "SAR is not extracted successfully. Assuming 1:1."; - pixel_width_ = 1; - pixel_height_ = 1; - } } VideoStreamInfo::~VideoStreamInfo() {} diff --git a/packager/media/base/video_stream_info.h b/packager/media/base/video_stream_info.h index 5b92825de4..be4867da04 100644 --- a/packager/media/base/video_stream_info.h +++ b/packager/media/base/video_stream_info.h @@ -67,6 +67,9 @@ class VideoStreamInfo : public StreamInfo { uint8_t nalu_length_size() const { return nalu_length_size_; } int16_t trick_play_rate() const { return trick_play_rate_; } + 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, diff --git a/packager/media/file/io_cache.cc b/packager/media/file/io_cache.cc index ae910328ef..1a3c71b75d 100644 --- a/packager/media/file/io_cache.cc +++ b/packager/media/file/io_cache.cc @@ -10,7 +10,7 @@ #include -#include "base/logging.h" +#include "packager/base/logging.h" namespace edash_packager { diff --git a/packager/media/filters/h264_parser.cc b/packager/media/filters/h264_parser.cc index 1b86001d37..f79f075391 100644 --- a/packager/media/filters/h264_parser.cc +++ b/packager/media/filters/h264_parser.cc @@ -20,9 +20,10 @@ namespace media { } \ } while (0) -void ExtractSarFromDecoderConfig( - const uint8_t* avc_decoder_config_data, size_t avc_decoder_config_data_size, - uint32_t* sar_width, uint32_t* sar_height) { +void ExtractSarFromDecoderConfig(const uint8_t* avc_decoder_config_data, + size_t avc_decoder_config_data_size, + uint32_t* sar_width, + uint32_t* sar_height) { BufferReader reader(avc_decoder_config_data, avc_decoder_config_data_size); uint8_t value = 0; // version check, must be 1. @@ -56,20 +57,28 @@ void ExtractSarFromDecoderConfig( uint16_t sps_length = 0; RCHECK(reader.Read2(&sps_length)); + ExtractSarFromSps(reader.data() + reader.pos(), sps_length, sar_width, + sar_height); + + // It is unlikely to have more than one SPS in practice. Also there's + // no way to change the sar_{width,height} dynamically from VideoStreamInfo. + // So skip the rest (if there are any). +} + +void ExtractSarFromSps(const uint8_t* sps_data, + size_t sps_data_size, + uint32_t* sar_width, + uint32_t* sar_height) { H264Parser parser; int sps_id; - RCHECK(parser.ParseSPSFromArray(reader.data() + reader.pos(), sps_length, - &sps_id) == H264Parser::kOk); + RCHECK(parser.ParseSPSFromArray(sps_data, sps_data_size, &sps_id) == + H264Parser::kOk); const H264SPS& sps = *parser.GetSPS(sps_id); // 0 means it wasn't in the SPS and therefore assume 1. *sar_width = sps.sar_width == 0 ? 1 : sps.sar_width; *sar_height = sps.sar_height == 0 ? 1 : sps.sar_height; DVLOG(2) << "Found sar_width: " << *sar_width << " sar_height: " << *sar_height; - - // It is unlikely to have more than one SPS in practice. Also there's - // no way to change the sar_{width,height} dynamically from VideoStreamInfo. - // So skip the rest (if there are any). } #undef RCHECK diff --git a/packager/media/filters/h264_parser.h b/packager/media/filters/h264_parser.h index d78257c536..77fc00171d 100644 --- a/packager/media/filters/h264_parser.h +++ b/packager/media/filters/h264_parser.h @@ -23,9 +23,18 @@ namespace media { // |avc_decoder_config_data|. // If the value is 0 or ommited in |avc_decoder_config_data|, then 1 is // assigned. -void ExtractSarFromDecoderConfig( - const uint8_t* avc_decoder_config_data, size_t avc_decoder_config_data_size, - uint32_t* sar_width, uint32_t* sar_height); +void ExtractSarFromDecoderConfig(const uint8_t* avc_decoder_config_data, + size_t avc_decoder_config_data_size, + uint32_t* sar_width, + uint32_t* sar_height); + +// |sps_data| must be a valid SPS specified in ISO/IEC 14496-10. +// On success, |sar_width| and |sar_height| contain pixel width and height +// respectively. +void ExtractSarFromSps(const uint8_t* sps_data, + size_t sps_data_size, + uint32_t* sar_width, + uint32_t* sar_height); // For explanations of each struct and its members, see H.264 specification // at http://www.itu.int/rec/T-REC-H.264. diff --git a/packager/media/filters/h264_parser_unittest.cc b/packager/media/filters/h264_parser_unittest.cc index 3b5bc05c1d..71a3ebec6a 100644 --- a/packager/media/filters/h264_parser_unittest.cc +++ b/packager/media/filters/h264_parser_unittest.cc @@ -6,7 +6,6 @@ #include "packager/base/logging.h" #include "packager/base/stl_util.h" -#include "packager/base/strings/string_number_conversions.h" #include "packager/media/test/test_data_util.h" #include "packager/media/filters/h264_parser.h" @@ -66,5 +65,33 @@ TEST(H264ParserTest, StreamFileParsing) { } } +TEST(H264ParserTest, ExtractSarFromDecoderConfig) { + 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 pixel_width = 0; + uint32_t pixel_height = 0; + ExtractSarFromDecoderConfig(kDecoderConfig, arraysize(kDecoderConfig), + &pixel_width, &pixel_height); + EXPECT_EQ(8u, pixel_width); + EXPECT_EQ(9u, pixel_height); +} + +TEST(H264ParserTest, ExtractSarFromSps) { + 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}; + + uint32_t pixel_width = 0; + uint32_t pixel_height = 0; + ExtractSarFromSps(kSps, arraysize(kSps), &pixel_width, &pixel_height); + EXPECT_EQ(8u, pixel_width); + EXPECT_EQ(9u, pixel_height); +} + } // namespace media } // namespace edash_packager diff --git a/packager/media/formats/mp4/mp4_media_parser.cc b/packager/media/formats/mp4/mp4_media_parser.cc index 8c682f6e8b..0c06e5577d 100644 --- a/packager/media/formats/mp4/mp4_media_parser.cc +++ b/packager/media/formats/mp4/mp4_media_parser.cc @@ -20,6 +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/formats/mp4/box_definitions.h" #include "packager/media/formats/mp4/box_reader.h" #include "packager/media/formats/mp4/es_descriptor.h" @@ -368,6 +369,15 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) { entry.avcc.profile_compatibility, entry.avcc.avc_level); + 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) { + if (!entry.avcc.sps_list.empty()) { + const std::vector& sps = entry.avcc.sps_list[0]; + ExtractSarFromSps(&sps[0], sps.size(), &pixel_width, &pixel_height); + } + } + 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, @@ -378,8 +388,8 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) { track->media.header.language, entry.width, entry.height, - entry.pixel_aspect.h_spacing, - entry.pixel_aspect.v_spacing, + pixel_width, + pixel_height, 0, // trick_play_rate entry.avcc.length_size, &entry.avcc.data[0], diff --git a/packager/media/formats/mp4/mp4_muxer.cc b/packager/media/formats/mp4/mp4_muxer.cc index 3b905376c2..c31907d472 100644 --- a/packager/media/formats/mp4/mp4_muxer.cc +++ b/packager/media/formats/mp4/mp4_muxer.cc @@ -161,9 +161,15 @@ void MP4Muxer::GenerateVideoTrak(const VideoStreamInfo* video_info, // width and height specify the track's visual presentation size as // fixed-point 16.16 values. + uint32_t pixel_width = video_info->pixel_width(); + uint32_t pixel_height = video_info->pixel_height(); + if (pixel_width == 0 || pixel_height == 0) { + LOG(WARNING) << "pixel width/height are not set. Assuming 1:1."; + pixel_width = 1; + pixel_height = 1; + } const double sample_aspect_ratio = - static_cast(video_info->pixel_width()) / - video_info->pixel_height(); + static_cast(pixel_width) / pixel_height; trak->header.width = video_info->width() * sample_aspect_ratio * 0x10000; trak->header.height = video_info->height() * 0x10000; @@ -174,9 +180,9 @@ void MP4Muxer::GenerateVideoTrak(const VideoStreamInfo* video_info, video.width = video_info->width(); video.height = video_info->height(); video.avcc.data = video_info->extra_data(); - if (video_info->pixel_width() != 1 || video_info->pixel_height() != 1) { - video.pixel_aspect.h_spacing = video_info->pixel_width(); - video.pixel_aspect.v_spacing = video_info->pixel_height(); + if (pixel_width != 1 || pixel_height != 1) { + video.pixel_aspect.h_spacing = pixel_width; + video.pixel_aspect.v_spacing = pixel_height; } SampleDescription& sample_description = diff --git a/packager/media/formats/wvm/wvm_media_parser.cc b/packager/media/formats/wvm/wvm_media_parser.cc index c8f90eee1e..4535e27439 100644 --- a/packager/media/formats/wvm/wvm_media_parser.cc +++ b/packager/media/formats/wvm/wvm_media_parser.cc @@ -15,6 +15,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/formats/mp2t/adts_header.h" #define HAS_HEADER_EXTENSION(x) ((x != 0xBC) && (x != 0xBE) && (x != 0xBF) \ @@ -805,6 +806,18 @@ bool WvmMediaParser::Output(bool output_encrypted_sample) { stream_infos_[i]->set_codec_string(VideoStreamInfo::GetCodecString( kCodecH264, decoder_config_record[1], decoder_config_record[2], decoder_config_record[3])); + + VideoStreamInfo* video_stream_info = + reinterpret_cast(stream_infos_[i].get()); + uint32_t pixel_width = video_stream_info->pixel_width(); + uint32_t pixel_height = video_stream_info->pixel_height(); + if (pixel_width == 0 || pixel_height == 0) { + ExtractSarFromDecoderConfig(&decoder_config_record[0], + decoder_config_record.size(), + &pixel_width, &pixel_height); + video_stream_info->set_pixel_width(pixel_width); + video_stream_info->set_pixel_height(pixel_height); + } } } }