diff options
Diffstat (limited to 'chromium/media/formats')
26 files changed, 406 insertions, 128 deletions
diff --git a/chromium/media/formats/BUILD.gn b/chromium/media/formats/BUILD.gn index 0b58533cbf1..1ed89cb5a83 100644 --- a/chromium/media/formats/BUILD.gn +++ b/chromium/media/formats/BUILD.gn @@ -72,7 +72,7 @@ source_set("formats") { deps = [ "//media/base", "//skia", - "//third_party/libaom:av1_features", + "//third_party/libaom:av1_buildflags", ] configs += [ @@ -162,6 +162,8 @@ static_library("test_support") { visibility = [ "//media:test_support" ] sources = [ + "common/stream_parser_test_base.cc", + "common/stream_parser_test_base.h", "webm/cluster_builder.cc", "webm/cluster_builder.h", "webm/opus_packet_builder.cc", @@ -178,22 +180,14 @@ static_library("test_support") { deps = [ "//base/test:test_support", "//media/base:test_support", + "//testing/gtest", ] - if (proprietary_codecs) { + if (proprietary_codecs && enable_mse_mpeg2ts_stream_parser) { sources += [ - "common/stream_parser_test_base.cc", - "common/stream_parser_test_base.h", + "mp2t/es_parser_test_base.cc", + "mp2t/es_parser_test_base.h", ] - - deps += [ "//testing/gtest" ] - - if (enable_mse_mpeg2ts_stream_parser) { - sources += [ - "mp2t/es_parser_test_base.cc", - "mp2t/es_parser_test_base.h", - ] - } } } @@ -202,6 +196,7 @@ source_set("unit_tests") { sources = [ "ac3/ac3_util_unittest.cc", "common/offset_byte_queue_unittest.cc", + "mpeg/mpeg1_audio_stream_parser_unittest.cc", "webm/webm_cluster_parser_unittest.cc", "webm/webm_content_encodings_client_unittest.cc", "webm/webm_crypto_helpers_unittest.cc", @@ -234,7 +229,6 @@ source_set("unit_tests") { "mp4/sample_to_group_iterator_unittest.cc", "mp4/track_run_iterator_unittest.cc", "mpeg/adts_stream_parser_unittest.cc", - "mpeg/mpeg1_audio_stream_parser_unittest.cc", ] deps += [ "//crypto" ] diff --git a/chromium/media/formats/ac3/ac3_util.cc b/chromium/media/formats/ac3/ac3_util.cc index 8d0b7869ec0..2c28262da9e 100644 --- a/chromium/media/formats/ac3/ac3_util.cc +++ b/chromium/media/formats/ac3/ac3_util.cc @@ -86,7 +86,7 @@ const uint8_t* FindNextSyncWord(const uint8_t* const begin, while (current < end - 1) { if (current[0] == 0x0B && current[1] == 0x77) { if (current != begin) - DVLOG(2) << __FUNCTION__ << " skip " << current - begin << " bytes."; + DVLOG(2) << __func__ << " skip " << current - begin << " bytes."; return current; } else if (current[1] != 0x0B) { @@ -124,7 +124,7 @@ int ParseAc3SyncFrameSize(Ac3Header& header) { if (header.sample_rate_code() >= arraysize(kSampleRate) || header.ac3_frame_size_code() >= arraysize(kSyncFrameSizeInWordsFor44kHz)) { - DVLOG(2) << __FUNCTION__ << " Invalid frame header." + DVLOG(2) << __func__ << " Invalid frame header." << " fscod:" << header.sample_rate_code() << " frmsizecod:" << header.ac3_frame_size_code(); return -1; @@ -171,15 +171,15 @@ int ParseTotalSampleCount(const uint8_t* data, size_t size, bool is_eac3) { if (frame_size > 0 && sample_count > 0) { current += frame_size; if (current > end) { - DVLOG(2) << __FUNCTION__ << " Incomplete frame, missing " - << current - end << " bytes."; + DVLOG(2) << __func__ << " Incomplete frame, missing " << current - end + << " bytes."; break; } total_sample_count += sample_count; } else { DVLOG(2) - << __FUNCTION__ + << __func__ << " Invalid frame, skip 2 bytes to find next synchronization word."; current += 2; } diff --git a/chromium/media/formats/mp2t/es_parser_adts.cc b/chromium/media/formats/mp2t/es_parser_adts.cc index f27c91bfcde..7a2dbb5c469 100644 --- a/chromium/media/formats/mp2t/es_parser_adts.cc +++ b/chromium/media/formats/mp2t/es_parser_adts.cc @@ -9,6 +9,7 @@ #include <vector> #include "base/logging.h" +#include "base/optional.h" #include "base/strings/string_number_conversions.h" #include "media/base/audio_timestamp_helper.h" #include "media/base/bit_reader.h" @@ -215,10 +216,11 @@ bool EsParserAdts::ParseFromEsQueue() { if (base_decrypt_config) { std::vector<SubsampleEntry> subsamples; CalculateSubsamplesForAdtsFrame(adts_frame, &subsamples); - std::unique_ptr<DecryptConfig> decrypt_config( - new DecryptConfig(base_decrypt_config->key_id(), - base_decrypt_config->iv(), subsamples)); - stream_parser_buffer->set_decrypt_config(std::move(decrypt_config)); + stream_parser_buffer->set_decrypt_config( + std::make_unique<DecryptConfig>( + base_decrypt_config->encryption_mode(), + base_decrypt_config->key_id(), base_decrypt_config->iv(), + subsamples, base_decrypt_config->encryption_pattern())); } } #endif diff --git a/chromium/media/formats/mp2t/es_parser_h264.cc b/chromium/media/formats/mp2t/es_parser_h264.cc index 3b2099f20a0..887b89879ef 100644 --- a/chromium/media/formats/mp2t/es_parser_h264.cc +++ b/chromium/media/formats/mp2t/es_parser_h264.cc @@ -466,9 +466,31 @@ bool EsParserH264::EmitFrame(int64_t access_unit_pos, stream_parser_buffer->set_timestamp(current_timing_desc.pts); #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES) if (use_hls_sample_aes_ && base_decrypt_config) { - std::unique_ptr<DecryptConfig> decrypt_config(new DecryptConfig( - base_decrypt_config->key_id(), base_decrypt_config->iv(), subsamples)); - stream_parser_buffer->set_decrypt_config(std::move(decrypt_config)); + switch (base_decrypt_config->encryption_mode()) { + case EncryptionMode::kUnencrypted: + // As |base_decrypt_config| is specified, the stream is encrypted, + // so this shouldn't happen. + NOTREACHED(); + break; + case EncryptionMode::kCenc: + stream_parser_buffer->set_decrypt_config( + DecryptConfig::CreateCencConfig(base_decrypt_config->key_id(), + base_decrypt_config->iv(), + subsamples)); + break; + case EncryptionMode::kCbcs: + // Note that for SampleAES the (encrypt,skip) pattern is constant. + // If not specified in |base_decrypt_config|, use default values. + stream_parser_buffer->set_decrypt_config( + DecryptConfig::CreateCbcsConfig( + base_decrypt_config->key_id(), base_decrypt_config->iv(), + subsamples, + base_decrypt_config->HasPattern() + ? base_decrypt_config->encryption_pattern() + : EncryptionPattern(kSampleAESEncryptBlocks, + kSampleAESSkipBlocks))); + break; + } } #endif return es_adapter_.OnNewBuffer(stream_parser_buffer); diff --git a/chromium/media/formats/mp2t/mp2t_stream_parser.cc b/chromium/media/formats/mp2t/mp2t_stream_parser.cc index cd4a8bccab6..60ccf910e2d 100644 --- a/chromium/media/formats/mp2t/mp2t_stream_parser.cc +++ b/chromium/media/formats/mp2t/mp2t_stream_parser.cc @@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/callback_helpers.h" +#include "base/optional.h" #include "media/base/media_tracks.h" #include "media/base/stream_parser_buffer.h" #include "media/base/text_track_config.h" @@ -843,8 +844,9 @@ void Mp2tStreamParser::UnregisterCat() { } void Mp2tStreamParser::RegisterCencPids(int ca_pid, int pssh_pid) { - std::unique_ptr<TsSectionCetsEcm> ecm_parser(new TsSectionCetsEcm(base::Bind( - &Mp2tStreamParser::RegisterDecryptConfig, base::Unretained(this)))); + std::unique_ptr<TsSectionCetsEcm> ecm_parser( + new TsSectionCetsEcm(base::BindRepeating( + &Mp2tStreamParser::RegisterNewKeyIdAndIv, base::Unretained(this)))); std::unique_ptr<PidState> ecm_pid_state( new PidState(ca_pid, PidState::kPidCetsEcm, std::move(ecm_parser))); ecm_pid_state->Enable(); @@ -883,12 +885,34 @@ void Mp2tStreamParser::RegisterEncryptionScheme( // Reset the DecryptConfig, so that unless and until a CENC-ECM (containing // key id and IV) is seen, media data will be considered unencrypted. This is // similar to the way clear leaders can occur in MP4 containers. - decrypt_config_.reset(nullptr); + decrypt_config_.reset(); } -void Mp2tStreamParser::RegisterDecryptConfig(const DecryptConfig& config) { - decrypt_config_.reset( - new DecryptConfig(config.key_id(), config.iv(), config.subsamples())); +void Mp2tStreamParser::RegisterNewKeyIdAndIv(const std::string& key_id, + const std::string& iv) { + if (!iv.empty()) { + switch (initial_scheme_.mode()) { + case EncryptionScheme::CIPHER_MODE_UNENCRYPTED: + decrypt_config_.reset(); + break; + case EncryptionScheme::CIPHER_MODE_AES_CTR: + decrypt_config_ = DecryptConfig::CreateCencConfig(key_id, iv, {}); + break; + case EncryptionScheme::CIPHER_MODE_AES_CBC: + // MP2 Transport Streams don't always specify the encryption pattern up + // front. Instead it is determined later by the stream type. So if the + // pattern is unknown, leave it out. + EncryptionPattern pattern = initial_scheme_.pattern(); + if (pattern.IsInEffect()) { + decrypt_config_ = + DecryptConfig::CreateCbcsConfig(key_id, iv, {}, pattern); + } else { + decrypt_config_ = + DecryptConfig::CreateCbcsConfig(key_id, iv, {}, base::nullopt); + } + break; + } + } } void Mp2tStreamParser::RegisterPsshBoxes( diff --git a/chromium/media/formats/mp2t/mp2t_stream_parser.h b/chromium/media/formats/mp2t/mp2t_stream_parser.h index 835fafe7400..e46327b723c 100644 --- a/chromium/media/formats/mp2t/mp2t_stream_parser.h +++ b/chromium/media/formats/mp2t/mp2t_stream_parser.h @@ -125,8 +125,8 @@ class MEDIA_EXPORT Mp2tStreamParser : public StreamParser { // be the case during an unencrypted portion of a live stream. void RegisterEncryptionScheme(const EncryptionScheme& scheme); - // Register the DecryptConfig (parsed from CENC-ECM). - void RegisterDecryptConfig(const DecryptConfig& config); + // Register the new KeyID and IV (parsed from CENC-ECM). + void RegisterNewKeyIdAndIv(const std::string& key_id, const std::string& iv); // Register the PSSH (parsed from CENC-PSSH). void RegisterPsshBoxes(const std::vector<uint8_t>& init_data); @@ -173,6 +173,9 @@ class MEDIA_EXPORT Mp2tStreamParser : public StreamParser { #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES) EncryptionScheme initial_scheme_; + + // TODO(jrummell): Rather than store the key_id and iv in a DecryptConfig, + // provide a better way to access the last values seen in a ECM packet. std::unique_ptr<DecryptConfig> decrypt_config_; #endif diff --git a/chromium/media/formats/mp2t/mp2t_stream_parser_unittest.cc b/chromium/media/formats/mp2t/mp2t_stream_parser_unittest.cc index 137a74246a2..a0ae6df897e 100644 --- a/chromium/media/formats/mp2t/mp2t_stream_parser_unittest.cc +++ b/chromium/media/formats/mp2t/mp2t_stream_parser_unittest.cc @@ -127,8 +127,7 @@ std::string DecryptBuffer(const StreamParserBuffer& buffer, EXPECT_TRUE(scheme.is_encrypted()); EXPECT_TRUE(scheme.mode() == EncryptionScheme::CIPHER_MODE_AES_CBC); bool has_pattern = scheme.pattern().IsInEffect(); - EXPECT_TRUE(!has_pattern || - scheme.pattern().Matches(EncryptionPattern(1, 9))); + EXPECT_TRUE(!has_pattern || scheme.pattern() == EncryptionPattern(1, 9)); std::string key; EXPECT_TRUE( diff --git a/chromium/media/formats/mp2t/ts_section_cets_ecm.cc b/chromium/media/formats/mp2t/ts_section_cets_ecm.cc index 1679c030718..a50dec10152 100644 --- a/chromium/media/formats/mp2t/ts_section_cets_ecm.cc +++ b/chromium/media/formats/mp2t/ts_section_cets_ecm.cc @@ -6,15 +6,14 @@ #include "base/logging.h" #include "media/base/bit_reader.h" -#include "media/base/decrypt_config.h" #include "media/formats/mp2t/mp2t_common.h" namespace media { namespace mp2t { TsSectionCetsEcm::TsSectionCetsEcm( - const RegisterDecryptConfigCb& register_decrypt_config_cb) - : register_decrypt_config_cb_(register_decrypt_config_cb) {} + const RegisterNewKeyIdAndIvCB& register_new_key_id_and_iv_cb) + : register_new_key_id_and_iv_cb_(register_new_key_id_and_iv_cb) {} TsSectionCetsEcm::~TsSectionCetsEcm() {} @@ -33,7 +32,6 @@ bool TsSectionCetsEcm::Parse(bool payload_unit_start_indicator, bool key_id_flag; int au_byte_offset_size; std::string iv; - std::vector<SubsampleEntry> subsamples_empty; // TODO(dougsteed). Currently we allow only a subset of the possible values. // When we flesh out this implementation to cover all of ISO/IEC 23001-9 we // will need to generalize this. @@ -67,8 +65,7 @@ bool TsSectionCetsEcm::Parse(bool payload_unit_start_indicator, // The CETS-ECM is supposed to use adaptation field stuffing to fill the TS // packet, so there should be no data left to read. RCHECK(bit_reader.bits_available() == 0); - DecryptConfig decrypt_config(key_id, iv, subsamples_empty); - register_decrypt_config_cb_.Run(decrypt_config); + register_new_key_id_and_iv_cb_.Run(key_id, iv); return true; } diff --git a/chromium/media/formats/mp2t/ts_section_cets_ecm.h b/chromium/media/formats/mp2t/ts_section_cets_ecm.h index c07be4a0d58..6d17b8bff37 100644 --- a/chromium/media/formats/mp2t/ts_section_cets_ecm.h +++ b/chromium/media/formats/mp2t/ts_section_cets_ecm.h @@ -7,24 +7,28 @@ #include <stdint.h> +#include <string> + #include "base/callback.h" #include "base/macros.h" -#include "media/base/byte_queue.h" #include "media/formats/mp2t/ts_section.h" namespace media { -class DecryptConfig; - namespace mp2t { class TsSectionCetsEcm : public TsSection { public: - // RegisterDecryptConfigCb::Run(const DecryptConfig& decrypt_config); - using RegisterDecryptConfigCb = - base::Callback<void(const DecryptConfig& decrypt_config)>; + // RegisterNewKeyIdAndIvCB() may be called multiple times. From + // ISO/IEC 23001-9:2016, section 7.2: "Key/IV information for every + // encrypted PID should be carried in a separate ECM PID." So there may be + // ECM's for each audio and video stream (and more if key rotation is used). + using RegisterNewKeyIdAndIvCB = + base::RepeatingCallback<void(const std::string& key_id, + const std::string& iv)>; + explicit TsSectionCetsEcm( - const RegisterDecryptConfigCb& register_decrypt_config_cb); + const RegisterNewKeyIdAndIvCB& register_new_key_id_and_iv_cb); ~TsSectionCetsEcm() override; // TsSection implementation. @@ -35,7 +39,7 @@ class TsSectionCetsEcm : public TsSection { void Reset() override; private: - RegisterDecryptConfigCb register_decrypt_config_cb_; + RegisterNewKeyIdAndIvCB register_new_key_id_and_iv_cb_; DISALLOW_COPY_AND_ASSIGN(TsSectionCetsEcm); }; diff --git a/chromium/media/formats/mp4/box_definitions.cc b/chromium/media/formats/mp4/box_definitions.cc index 307419e733f..6def180d143 100644 --- a/chromium/media/formats/mp4/box_definitions.cc +++ b/chromium/media/formats/mp4/box_definitions.cc @@ -17,7 +17,7 @@ #include "media/formats/mp4/es_descriptor.h" #include "media/formats/mp4/rcheck.h" #include "media/media_buildflags.h" -#include "third_party/libaom/av1_features.h" +#include "third_party/libaom/av1_buildflags.h" #if BUILDFLAG(USE_PROPRIETARY_CODECS) #include "media/formats/mp4/avc.h" @@ -341,16 +341,25 @@ bool ProtectionSchemeInfo::Parse(BoxReader* reader) { } bool ProtectionSchemeInfo::HasSupportedScheme() const { - FourCC fourCC = type.type; - if (fourCC == FOURCC_CENC) + FourCC four_cc = type.type; + if (four_cc == FOURCC_CENC) return true; #if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) - if (fourCC == FOURCC_CBCS) + if (four_cc == FOURCC_CBCS) return true; #endif return false; } +bool ProtectionSchemeInfo::IsCbcsEncryptionScheme() const { +#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) + FourCC four_cc = type.type; + return (four_cc == FOURCC_CBCS); +#else + return false; +#endif +} + MovieHeader::MovieHeader() : version(0), creation_time(0), @@ -386,7 +395,7 @@ bool MovieHeader::Parse(BoxReader* reader) { RCHECK(reader->Read4s(&rate) && reader->Read2s(&volume) && reader->SkipBytes(10) && // reserved - reader->SkipBytes(36) && // matrix + reader->ReadDisplayMatrix(display_matrix) && reader->SkipBytes(24) && // predefined zero reader->Read4(&next_track_id)); return true; @@ -427,7 +436,7 @@ bool TrackHeader::Parse(BoxReader* reader) { reader->Read2s(&alternate_group) && reader->Read2s(&volume) && reader->SkipBytes(2) && // reserved - reader->SkipBytes(36) && // matrix + reader->ReadDisplayMatrix(display_matrix) && reader->Read4(&width) && reader->Read4(&height)); @@ -1031,10 +1040,6 @@ bool AudioSampleEntry::Parse(BoxReader* reader) { // Read the FLACSpecificBox, even if CENC is signalled. if (format == FOURCC_FLAC || (format == FOURCC_ENCA && sinf.format.format == FOURCC_FLAC)) { - RCHECK_MEDIA_LOGGED(base::FeatureList::IsEnabled(kMseFlacInIsobmff), - reader->media_log(), - "MSE support for FLAC in MP4 is not enabled."); - RCHECK_MEDIA_LOGGED(reader->ReadChild(&dfla), reader->media_log(), "Failure parsing FLACSpecificBox (dfLa)"); diff --git a/chromium/media/formats/mp4/box_definitions.h b/chromium/media/formats/mp4/box_definitions.h index c251c8b0e18..847c6b7e86b 100644 --- a/chromium/media/formats/mp4/box_definitions.h +++ b/chromium/media/formats/mp4/box_definitions.h @@ -155,6 +155,7 @@ struct MEDIA_EXPORT ProtectionSchemeInfo : Box { SchemeInfo info; bool HasSupportedScheme() const; + bool IsCbcsEncryptionScheme() const; }; struct MEDIA_EXPORT MovieHeader : Box { @@ -167,6 +168,12 @@ struct MEDIA_EXPORT MovieHeader : Box { uint64_t duration; int32_t rate; int16_t volume; + // A 3x3 matrix of [ A B C ] + // [ D E F ] + // [ U V W ] + // Where A-F are 16.16 fixed point decimals + // And U, V, W are 2.30 fixed point decimals. + DisplayMatrix display_matrix; uint32_t next_track_id; }; @@ -180,6 +187,7 @@ struct MEDIA_EXPORT TrackHeader : Box { int16_t layer; int16_t alternate_group; int16_t volume; + DisplayMatrix display_matrix; // See MovieHeader.display_matrix uint32_t width; uint32_t height; }; diff --git a/chromium/media/formats/mp4/box_reader.cc b/chromium/media/formats/mp4/box_reader.cc index bf7e2653c79..cbcd48cff26 100644 --- a/chromium/media/formats/mp4/box_reader.cc +++ b/chromium/media/formats/mp4/box_reader.cc @@ -204,6 +204,15 @@ bool BoxReader::ScanChildren() { return true; } +bool BoxReader::ReadDisplayMatrix(DisplayMatrix matrix) { + for (int i = 0; i < kDisplayMatrixDimension; i++) { + if (!Read4s(&matrix[i])) { + return false; + } + } + return true; +} + bool BoxReader::HasChild(Box* child) { DCHECK(scanned_); DCHECK(child); diff --git a/chromium/media/formats/mp4/box_reader.h b/chromium/media/formats/mp4/box_reader.h index 140818aaa4a..2da377323fd 100644 --- a/chromium/media/formats/mp4/box_reader.h +++ b/chromium/media/formats/mp4/box_reader.h @@ -24,6 +24,14 @@ namespace media { namespace mp4 { +enum DisplayMatrixSize { + kDisplayMatrixWidth = 3, + kDisplayMatrixHeight = 3, + kDisplayMatrixDimension = kDisplayMatrixHeight * kDisplayMatrixWidth +}; + +using DisplayMatrix = int32_t[kDisplayMatrixDimension]; + class BoxReader; struct MEDIA_EXPORT Box { @@ -145,6 +153,10 @@ class MEDIA_EXPORT BoxReader : public BufferReader { // read or on child absent. bool MaybeReadChild(Box* child) WARN_UNUSED_RESULT; + // ISO-BMFF streams files use a 3x3 matrix consisting of 6 16.16 fixed point + // decimals and 3 2.30 fixed point decimals. + bool ReadDisplayMatrix(DisplayMatrix matrix); + // Read at least one child. False means error or no such child present. template<typename T> bool ReadChildren( std::vector<T>* children) WARN_UNUSED_RESULT; diff --git a/chromium/media/formats/mp4/fourccs.h b/chromium/media/formats/mp4/fourccs.h index bdf3d5faf5e..6d028ac788a 100644 --- a/chromium/media/formats/mp4/fourccs.h +++ b/chromium/media/formats/mp4/fourccs.h @@ -8,7 +8,7 @@ #include <string> #include "media/media_buildflags.h" -#include "third_party/libaom/av1_features.h" +#include "third_party/libaom/av1_buildflags.h" namespace media { namespace mp4 { @@ -67,6 +67,9 @@ enum FourCC { FOURCC_META = 0x6d657461, FOURCC_MFHD = 0x6d666864, FOURCC_MFRA = 0x6d667261, +#if BUILDFLAG(ENABLE_MPEG_H_AUDIO_DEMUXING) + FOURCC_MHM1 = 0x6d686d31, +#endif FOURCC_MINF = 0x6d696e66, FOURCC_MOOF = 0x6d6f6f66, FOURCC_MOOV = 0x6d6f6f76, diff --git a/chromium/media/formats/mp4/mp4_stream_parser.cc b/chromium/media/formats/mp4/mp4_stream_parser.cc index f2027534916..ee14479e26a 100644 --- a/chromium/media/formats/mp4/mp4_stream_parser.cc +++ b/chromium/media/formats/mp4/mp4_stream_parser.cc @@ -13,6 +13,7 @@ #include "base/callback_helpers.h" #include "base/logging.h" +#include "base/numerics/math_constants.h" #include "base/strings/string_number_conversions.h" #include "base/time/time.h" #include "build/build_config.h" @@ -37,6 +38,7 @@ namespace media { namespace mp4 { namespace { + const int kMaxEmptySampleLogs = 20; const int kMaxInvalidConversionLogs = 20; @@ -89,7 +91,6 @@ MP4StreamParser::MP4StreamParser(const std::set<int>& audio_object_types, has_flac_(has_flac), num_empty_samples_skipped_(0), num_invalid_conversions_(0) { - DCHECK(!has_flac || base::FeatureList::IsEnabled(kMseFlacInIsobmff)); } MP4StreamParser::~MP4StreamParser() = default; @@ -238,13 +239,77 @@ ParseResult MP4StreamParser::ParseBox() { return ParseResult::kOk; } +static inline double FixedToFloatingPoint(const int32_t& i) { + return static_cast<double>(i >> 16); +} + +VideoRotation MP4StreamParser::CalculateRotation(const TrackHeader& track, + const MovieHeader& movie) { + static_assert(kDisplayMatrixDimension == 9, "Display matrix must be 3x3"); + // 3x3 matrix: [ a b c ] + // [ d e f ] + // [ x y z ] + int32_t rotation_matrix[kDisplayMatrixDimension] = {0}; + + // Shift values for fixed point multiplications. + const int32_t shifts[kDisplayMatrixHeight] = {16, 16, 30}; + + // Matrix multiplication for + // track.display_matrix * movie.display_matrix + // with special consideration taken that entries a-f are 16.16 fixed point + // decimals and x-z are 2.30 fixed point decimals. + for (int i = 0; i < kDisplayMatrixWidth; i++) { + for (int j = 0; j < kDisplayMatrixHeight; j++) { + for (int e = 0; e < kDisplayMatrixHeight; e++) { + rotation_matrix[i * kDisplayMatrixHeight + j] += + ((int64_t)track.display_matrix[i * kDisplayMatrixHeight + e] * + movie.display_matrix[e * kDisplayMatrixHeight + j]) >> + shifts[e]; + } + } + } + + // Rotation by angle Θ is represented in the matrix as: + // [ cos(Θ), -sin(Θ), ...] + // [ sin(Θ), cos(Θ), ...] + // [ ..., ..., 1 ] + // But we only need cos(Θ) for the angle and sin(Θ) for the quadrant. + double angle = acos(FixedToFloatingPoint(rotation_matrix[0])) + * 180 / base::kPiDouble; + + if (angle < 0) + angle += 360; + + if (angle >= 360) + angle -= 360; + + // 16 bits of fixed point decimal is enough to give 6 decimals of precision + // to cos(Θ). A delta of ±0.000001 causes acos(cos(Θ)) to differ by a minimum + // of 0.0002, which is why we only need to check that the angle is only + // accurate to within four decimal places. This is preferred to checking for + // a more precise accuracy, as the 'double' type is architecture dependant and + // ther may variance in floating point errors. + if (abs(angle - 0) < 1e-4) + return VIDEO_ROTATION_0; + + if (abs(angle - 180) < 1e-4) + return VIDEO_ROTATION_180; + + if (abs(angle - 90) < 1e-4) { + bool quadrant = asin(FixedToFloatingPoint(rotation_matrix[3])) < 0; + return quadrant ? VIDEO_ROTATION_90 : VIDEO_ROTATION_270; + } + + // TODO(tmathmeyer): Record this event and the faulty matrix somewhere. + return VIDEO_ROTATION_0; +} + bool MP4StreamParser::ParseMoov(BoxReader* reader) { moov_.reset(new Movie); RCHECK(moov_->Parse(reader)); runs_.reset(); audio_track_ids_.clear(); video_track_ids_.clear(); - is_track_encrypted_.clear(); has_audio_ = false; has_video_ = false; @@ -292,12 +357,14 @@ bool MP4StreamParser::ParseMoov(BoxReader* reader) { ? entry.sinf.format.format : entry.format; + if (audio_format != FOURCC_FLAC && #if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING) - if (audio_format != FOURCC_MP4A && audio_format != FOURCC_FLAC && - audio_format != FOURCC_AC3 && audio_format != FOURCC_EAC3) { -#else - if (audio_format != FOURCC_MP4A && audio_format != FOURCC_FLAC) { + audio_format != FOURCC_AC3 && audio_format != FOURCC_EAC3 && #endif +#if BUILDFLAG(ENABLE_MPEG_H_AUDIO_DEMUXING) + audio_format != FOURCC_MHM1 && +#endif + audio_format != FOURCC_MP4A) { MEDIA_LOG(ERROR, media_log_) << "Unsupported audio format 0x" << std::hex << entry.format << " in stsd box."; @@ -324,6 +391,13 @@ bool MP4StreamParser::ParseMoov(BoxReader* reader) { sample_per_second = entry.samplerate; extra_data = entry.dfla.stream_info; #if BUILDFLAG(USE_PROPRIETARY_CODECS) +#if BUILDFLAG(ENABLE_MPEG_H_AUDIO_DEMUXING) + } else if (audio_format == FOURCC_MHM1) { + codec = kCodecMpegHAudio; + channel_layout = CHANNEL_LAYOUT_BITSTREAM; + sample_per_second = entry.samplerate; + extra_data = entry.dfla.stream_info; +#endif } else { uint8_t audio_type = entry.esds.object_type; #if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING) @@ -394,7 +468,6 @@ bool MP4StreamParser::ParseMoov(BoxReader* reader) { return false; } bool is_track_encrypted = entry.sinf.info.track_encryption.is_encrypted; - is_track_encrypted_[audio_track_id] = is_track_encrypted; EncryptionScheme scheme = Unencrypted(); if (is_track_encrypted) { scheme = GetEncryptionScheme(entry.sinf); @@ -463,7 +536,6 @@ bool MP4StreamParser::ParseMoov(BoxReader* reader) { return false; } bool is_track_encrypted = entry.sinf.info.track_encryption.is_encrypted; - is_track_encrypted_[video_track_id] = is_track_encrypted; EncryptionScheme scheme = Unencrypted(); if (is_track_encrypted) { scheme = GetEncryptionScheme(entry.sinf); @@ -472,8 +544,8 @@ bool MP4StreamParser::ParseMoov(BoxReader* reader) { } video_config.Initialize(entry.video_codec, entry.video_codec_profile, PIXEL_FORMAT_I420, COLOR_SPACE_HD_REC709, - VIDEO_ROTATION_0, coded_size, visible_rect, - natural_size, + CalculateRotation(track->header, moov_->header), + coded_size, visible_rect, natural_size, // No decoder-specific buffer needed for AVC; // SPS/PPS are embedded in the video stream EmptyExtraData(), scheme); @@ -753,15 +825,12 @@ ParseResult MP4StreamParser::EnqueueSample(BufferQueueMap* buffers) { if (decrypt_config) { if (!subsamples.empty()) { // Create a new config with the updated subsamples. - decrypt_config.reset(new DecryptConfig(decrypt_config->key_id(), - decrypt_config->iv(), subsamples)); + decrypt_config.reset( + new DecryptConfig(decrypt_config->encryption_mode(), + decrypt_config->key_id(), decrypt_config->iv(), + subsamples, decrypt_config->encryption_pattern())); } // else, use the existing config. - } else if (is_track_encrypted_[runs_->track_id()]) { - // The media pipeline requires a DecryptConfig with an empty |iv|. - // TODO(ddorwin): Refactor so we do not need a fake key ID ("1"); - decrypt_config.reset( - new DecryptConfig("1", "", std::vector<SubsampleEntry>())); } StreamParserBuffer::Type buffer_type = audio ? DemuxerStream::AUDIO : diff --git a/chromium/media/formats/mp4/mp4_stream_parser.h b/chromium/media/formats/mp4/mp4_stream_parser.h index 97bdfd66972..585a789e807 100644 --- a/chromium/media/formats/mp4/mp4_stream_parser.h +++ b/chromium/media/formats/mp4/mp4_stream_parser.h @@ -28,6 +28,8 @@ namespace media { namespace mp4 { struct Movie; +struct MovieHeader; +struct TrackHeader; class BoxReader; class MEDIA_EXPORT MP4StreamParser : public StreamParser { @@ -48,6 +50,10 @@ class MEDIA_EXPORT MP4StreamParser : public StreamParser { void Flush() override; bool Parse(const uint8_t* buf, int size) override; + // Calculates the rotation value from the track header display matricies. + VideoRotation CalculateRotation(const TrackHeader& track, + const MovieHeader& movie); + private: enum State { kWaitingForInit, @@ -134,7 +140,6 @@ class MEDIA_EXPORT MP4StreamParser : public StreamParser { const std::set<int> audio_object_types_; const bool has_sbr_; const bool has_flac_; - std::map<uint32_t, bool> is_track_encrypted_; // Tracks the number of MEDIA_LOGS for skipping empty trun samples. int num_empty_samples_skipped_; diff --git a/chromium/media/formats/mp4/mp4_stream_parser_unittest.cc b/chromium/media/formats/mp4/mp4_stream_parser_unittest.cc index 588ebafa7d3..dac384d7c87 100644 --- a/chromium/media/formats/mp4/mp4_stream_parser_unittest.cc +++ b/chromium/media/formats/mp4/mp4_stream_parser_unittest.cc @@ -10,6 +10,7 @@ #include <algorithm> #include <memory> #include <string> +#include <tuple> #include "base/bind.h" #include "base/bind_helpers.h" @@ -33,6 +34,7 @@ #include "media/formats/mp4/fourccs.h" #include "media/media_buildflags.h" #include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest-param-test.h" #include "testing/gtest/include/gtest/gtest.h" using ::testing::InSequence; @@ -470,10 +472,6 @@ TEST_F(MP4StreamParserTest, DemuxingEAC3) { } TEST_F(MP4StreamParserTest, Flac) { - // The feature is disabled by default. Enable it. - base::test::ScopedFeatureList features; - features.InitAndEnableFeature(kMseFlacInIsobmff); - parser_.reset(new MP4StreamParser(std::set<int>(), false, true)); auto params = GetDefaultInitParametersExpectations(); @@ -485,10 +483,6 @@ TEST_F(MP4StreamParserTest, Flac) { } TEST_F(MP4StreamParserTest, Flac192kHz) { - // The feature is disabled by default. Enable it. - base::test::ScopedFeatureList features; - features.InitAndEnableFeature(kMseFlacInIsobmff); - parser_.reset(new MP4StreamParser(std::set<int>(), false, true)); auto params = GetDefaultInitParametersExpectations(); @@ -586,5 +580,55 @@ TEST_F(MP4StreamParserTest, MultiTrackFile) { EXPECT_EQ(audio_track2.language(), "und"); } +// <cos(θ), sin(θ), θ expressed as a rotation Enum> +using MatrixRotationTestCaseParam = std::tuple<double, double, VideoRotation>; + +class MP4StreamParserRotationMatrixEvaluatorTest + : public ::testing::TestWithParam<MatrixRotationTestCaseParam> { + public: + MP4StreamParserRotationMatrixEvaluatorTest() { + std::set<int> audio_object_types; + audio_object_types.insert(kISO_14496_3); + parser_.reset(new MP4StreamParser(audio_object_types, false, false)); + } + + protected: + std::unique_ptr<MP4StreamParser> parser_; +}; + +TEST_P(MP4StreamParserRotationMatrixEvaluatorTest, RotationCalculation) { + TrackHeader track_header; + MovieHeader movie_header; + + // Identity matrix, with 16.16 and 2.30 fixed points. + uint32_t identity_matrix[9] = {1 << 16, 0, 0, 0, 1 << 16, 0, 0, 0, 1 << 30}; + + memcpy(movie_header.display_matrix, identity_matrix, sizeof(identity_matrix)); + memcpy(track_header.display_matrix, identity_matrix, sizeof(identity_matrix)); + + MatrixRotationTestCaseParam data = GetParam(); + + // Insert fixed point decimal data into the rotation matrix. + track_header.display_matrix[0] = std::get<0>(data) * (1 << 16); + track_header.display_matrix[4] = std::get<0>(data) * (1 << 16); + track_header.display_matrix[1] = -(std::get<1>(data) * (1 << 16)); + track_header.display_matrix[3] = std::get<1>(data) * (1 << 16); + + EXPECT_EQ(parser_->CalculateRotation(track_header, movie_header), + std::get<2>(data)); +} + +MatrixRotationTestCaseParam rotation_test_cases[6] = { + {1, 0, VIDEO_ROTATION_0}, // cos(0) = 1, sin(0) = 0 + {0, -1, VIDEO_ROTATION_90}, // cos(90) = 0, sin(90) =-1 + {-1, 0, VIDEO_ROTATION_180}, // cos(180)=-1, sin(180)= 0 + {0, 1, VIDEO_ROTATION_270}, // cos(270)= 0, sin(270)= 1 + {1, 1, VIDEO_ROTATION_0}, // Error case + {5, 5, VIDEO_ROTATION_0}, // Error case +}; +INSTANTIATE_TEST_CASE_P(CheckMath, + MP4StreamParserRotationMatrixEvaluatorTest, + testing::ValuesIn(rotation_test_cases)); + } // namespace mp4 } // namespace media diff --git a/chromium/media/formats/mp4/track_run_iterator.cc b/chromium/media/formats/mp4/track_run_iterator.cc index 1e35058e6cd..cb797448675 100644 --- a/chromium/media/formats/mp4/track_run_iterator.cc +++ b/chromium/media/formats/mp4/track_run_iterator.cc @@ -13,6 +13,8 @@ #include "base/numerics/checked_math.h" #include "base/numerics/safe_conversions.h" #include "media/base/demuxer_memory_limit.h" +#include "media/base/encryption_scheme.h" +#include "media/base/media_util.h" #include "media/base/timestamp_constants.h" #include "media/formats/mp4/rcheck.h" #include "media/formats/mp4/sample_to_group_iterator.h" @@ -52,6 +54,8 @@ struct TrackRunInfo { std::vector<uint8_t> aux_info_sizes; // Populated if default_size == 0. int aux_info_total_size; + EncryptionScheme encryption_scheme; + std::vector<CencSampleEncryptionInfoEntry> fragment_sample_encryption_info; TrackRunInfo(); @@ -342,20 +346,40 @@ bool TrackRunIterator::Init(const MovieFragment& moof) { traf.sample_group_description.entries; const TrackEncryption* track_encryption; + const ProtectionSchemeInfo* sinf; tri.is_audio = (stsd.type == kAudio); if (tri.is_audio) { RCHECK(!stsd.audio_entries.empty()); if (desc_idx >= stsd.audio_entries.size()) desc_idx = 0; tri.audio_description = &stsd.audio_entries[desc_idx]; + sinf = &tri.audio_description->sinf; track_encryption = &tri.audio_description->sinf.info.track_encryption; } else { RCHECK(!stsd.video_entries.empty()); if (desc_idx >= stsd.video_entries.size()) desc_idx = 0; tri.video_description = &stsd.video_entries[desc_idx]; + sinf = &tri.video_description->sinf; track_encryption = &tri.video_description->sinf.info.track_encryption; } + + if (!sinf->HasSupportedScheme()) { + tri.encryption_scheme = Unencrypted(); + } else { +#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) + tri.encryption_scheme = EncryptionScheme( + sinf->IsCbcsEncryptionScheme() + ? EncryptionScheme::CIPHER_MODE_AES_CBC + : EncryptionScheme::CIPHER_MODE_AES_CTR, + EncryptionPattern(track_encryption->default_crypt_byte_block, + track_encryption->default_skip_byte_block)); +#else + DCHECK(!sinf->IsCbcsEncryptionScheme()); + tri.encryption_scheme = AesCtrEncryptionScheme(); +#endif + } + // Initialize aux_info variables only if no sample encryption entries. if (sample_encryption_entries_count == 0 && traf.auxiliary_offset.offsets.size() > j) { @@ -670,16 +694,21 @@ bool TrackRunIterator::is_keyframe() const { return sample_itr_->is_keyframe; } -const TrackEncryption& TrackRunIterator::track_encryption() const { +const ProtectionSchemeInfo& TrackRunIterator::protection_scheme_info() const { if (is_audio()) - return audio_description().sinf.info.track_encryption; - return video_description().sinf.info.track_encryption; + return audio_description().sinf; + return video_description().sinf; +} + +const TrackEncryption& TrackRunIterator::track_encryption() const { + return protection_scheme_info().info.track_encryption; } std::unique_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() { DCHECK(is_encrypted()); size_t sample_idx = sample_itr_ - run_itr_->samples.begin(); const std::vector<uint8_t>& kid = GetKeyId(sample_idx); + std::string key_id(kid.begin(), kid.end()); if (run_itr_->sample_encryption_entries.empty()) { DCHECK_EQ(0, aux_info_size()); @@ -688,36 +717,60 @@ std::unique_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() { // with full sample encryption. That case will fall through to here. SampleEncryptionEntry sample_encryption_entry; if (ApplyConstantIv(sample_idx, &sample_encryption_entry)) { - return std::unique_ptr<DecryptConfig>(new DecryptConfig( - std::string(reinterpret_cast<const char*>(&kid[0]), kid.size()), - std::string(reinterpret_cast<const char*>( - sample_encryption_entry.initialization_vector), - arraysize(sample_encryption_entry.initialization_vector)), - sample_encryption_entry.subsamples)); + std::string iv(reinterpret_cast<const char*>( + sample_encryption_entry.initialization_vector), + arraysize(sample_encryption_entry.initialization_vector)); + switch (run_itr_->encryption_scheme.mode()) { + case EncryptionScheme::CIPHER_MODE_UNENCRYPTED: + return nullptr; + case EncryptionScheme::CIPHER_MODE_AES_CTR: + return DecryptConfig::CreateCencConfig( + key_id, iv, sample_encryption_entry.subsamples); + case EncryptionScheme::CIPHER_MODE_AES_CBC: + return DecryptConfig::CreateCbcsConfig( + key_id, iv, sample_encryption_entry.subsamples, + run_itr_->encryption_scheme.pattern()); + } } #endif MEDIA_LOG(ERROR, media_log_) << "Sample encryption info is not available."; - return std::unique_ptr<DecryptConfig>(); + return nullptr; } DCHECK_LT(sample_idx, run_itr_->sample_encryption_entries.size()); const SampleEncryptionEntry& sample_encryption_entry = run_itr_->sample_encryption_entries[sample_idx]; + std::string iv(reinterpret_cast<const char*>( + sample_encryption_entry.initialization_vector), + arraysize(sample_encryption_entry.initialization_vector)); size_t total_size = 0; if (!sample_encryption_entry.subsamples.empty() && (!sample_encryption_entry.GetTotalSizeOfSubsamples(&total_size) || total_size != static_cast<size_t>(sample_size()))) { MEDIA_LOG(ERROR, media_log_) << "Incorrect CENC subsample size."; - return std::unique_ptr<DecryptConfig>(); + return nullptr; } - return std::unique_ptr<DecryptConfig>(new DecryptConfig( - std::string(reinterpret_cast<const char*>(&kid[0]), kid.size()), - std::string(reinterpret_cast<const char*>( - sample_encryption_entry.initialization_vector), - arraysize(sample_encryption_entry.initialization_vector)), - sample_encryption_entry.subsamples)); +#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) + if (protection_scheme_info().IsCbcsEncryptionScheme()) { + uint32_t index = GetGroupDescriptionIndex(sample_idx); + uint32_t encrypt_blocks = + (index == 0) + ? track_encryption().default_crypt_byte_block + : GetSampleEncryptionInfoEntry(*run_itr_, index)->crypt_byte_block; + uint32_t skip_blocks = + (index == 0) + ? track_encryption().default_skip_byte_block + : GetSampleEncryptionInfoEntry(*run_itr_, index)->skip_byte_block; + return DecryptConfig::CreateCbcsConfig( + key_id, iv, sample_encryption_entry.subsamples, + EncryptionPattern(encrypt_blocks, skip_blocks)); + } +#endif + + return DecryptConfig::CreateCencConfig(key_id, iv, + sample_encryption_entry.subsamples); } uint32_t TrackRunIterator::GetGroupDescriptionIndex( diff --git a/chromium/media/formats/mp4/track_run_iterator.h b/chromium/media/formats/mp4/track_run_iterator.h index 59521c36c50..213acd1f0f4 100644 --- a/chromium/media/formats/mp4/track_run_iterator.h +++ b/chromium/media/formats/mp4/track_run_iterator.h @@ -95,6 +95,7 @@ class MEDIA_EXPORT TrackRunIterator { private: bool UpdateCts(); bool ResetRun(); + const ProtectionSchemeInfo& protection_scheme_info() const; const TrackEncryption& track_encryption() const; uint32_t GetGroupDescriptionIndex(uint32_t sample_index) const; diff --git a/chromium/media/formats/mpeg/mpeg_audio_stream_parser_base.cc b/chromium/media/formats/mpeg/mpeg_audio_stream_parser_base.cc index 80be6da0546..8717ac299f6 100644 --- a/chromium/media/formats/mpeg/mpeg_audio_stream_parser_base.cc +++ b/chromium/media/formats/mpeg/mpeg_audio_stream_parser_base.cc @@ -8,7 +8,6 @@ #include "base/bind.h" #include "base/callback_helpers.h" -#include "base/message_loop/message_loop.h" #include "media/base/media_log.h" #include "media/base/media_tracks.h" #include "media/base/media_util.h" diff --git a/chromium/media/formats/webm/webm_crypto_helpers.cc b/chromium/media/formats/webm/webm_crypto_helpers.cc index 1f8447ab8bd..846e6b7650a 100644 --- a/chromium/media/formats/webm/webm_crypto_helpers.cc +++ b/chromium/media/formats/webm/webm_crypto_helpers.cc @@ -106,10 +106,6 @@ bool WebMCreateDecryptConfig(const uint8_t* data, const uint8_t signal_byte = data[0]; int frame_offset = sizeof(signal_byte); - - // Setting the DecryptConfig object of the buffer while leaving the - // initialization vector empty will tell the decryptor that the frame is - // unencrypted. std::string counter_block; std::vector<SubsampleEntry> subsample_entries; @@ -145,9 +141,14 @@ bool WebMCreateDecryptConfig(const uint8_t* data, } } - decrypt_config->reset(new DecryptConfig( - std::string(reinterpret_cast<const char*>(key_id), key_id_size), - counter_block, subsample_entries)); + if (counter_block.empty()) { + // If the frame is unencrypted the DecryptConfig object should be NULL. + decrypt_config->reset(); + } else { + *decrypt_config = DecryptConfig::CreateCencConfig( + std::string(reinterpret_cast<const char*>(key_id), key_id_size), + counter_block, subsample_entries); + } *data_offset = frame_offset; return true; diff --git a/chromium/media/formats/webm/webm_crypto_helpers.h b/chromium/media/formats/webm/webm_crypto_helpers.h index 21e53f7409d..e1bf6c48115 100644 --- a/chromium/media/formats/webm/webm_crypto_helpers.h +++ b/chromium/media/formats/webm/webm_crypto_helpers.h @@ -14,11 +14,11 @@ namespace media { -// Fills an initialized DecryptConfig, which can be sent to the Decryptor if -// the stream has potentially encrypted frames. Also sets |data_offset| which -// indicates where the encrypted data starts. Leaving the IV empty will tell -// the decryptor that the frame is unencrypted. Returns true if |data| is valid, -// false otherwise, in which case |decrypt_config| and |data_offset| will not be +// Fills |decrypt_config|, which can be sent to the Decryptor if the stream +// has potentially encrypted frames. Also sets |data_offset| which indicates +// where the encrypted data starts. If the frame is unencrypted +// |*decrypt_config| will be null. Returns true if |data| is valid, false +// otherwise, in which case |decrypt_config| and |data_offset| will not be // changed. Current encrypted WebM request for comments specification is here // http://wiki.webmproject.org/encryption/webm-encryption-rfc bool MEDIA_EXPORT diff --git a/chromium/media/formats/webm/webm_crypto_helpers_unittest.cc b/chromium/media/formats/webm/webm_crypto_helpers_unittest.cc index e6e184fa184..842cc0d7289 100644 --- a/chromium/media/formats/webm/webm_crypto_helpers_unittest.cc +++ b/chromium/media/formats/webm/webm_crypto_helpers_unittest.cc @@ -37,7 +37,7 @@ TEST(WebMCryptoHelpersTest, ClearData) { sizeof(kKeyId), &decrypt_config, &data_offset)); EXPECT_EQ(1, data_offset); - EXPECT_FALSE(decrypt_config->is_encrypted()); + EXPECT_FALSE(decrypt_config); } TEST(WebMCryptoHelpersTest, EncryptedButNotEnoughBytes) { @@ -68,7 +68,7 @@ TEST(WebMCryptoHelpersTest, EncryptedNotPartitioned) { ASSERT_TRUE(WebMCreateDecryptConfig(kData, sizeof(kData), kKeyId, sizeof(kKeyId), &decrypt_config, &data_offset)); - EXPECT_TRUE(decrypt_config->is_encrypted()); + EXPECT_TRUE(decrypt_config); EXPECT_EQ(std::string(kKeyId, kKeyId + sizeof(kKeyId)), decrypt_config->key_id()); EXPECT_EQ(std::string(kExpectedIv, kExpectedIv + sizeof(kExpectedIv)), @@ -191,7 +191,7 @@ TEST(WebMCryptoHelpersTest, EncryptedPartitionedEvenNumberOfPartitions) { ASSERT_TRUE(WebMCreateDecryptConfig(kData, sizeof(kData), kKeyId, sizeof(kKeyId), &decrypt_config, &data_offset)); - EXPECT_TRUE(decrypt_config->is_encrypted()); + EXPECT_TRUE(decrypt_config); EXPECT_EQ(std::string(kKeyId, kKeyId + sizeof(kKeyId)), decrypt_config->key_id()); EXPECT_EQ(std::string(kExpectedIv, kExpectedIv + sizeof(kExpectedIv)), @@ -224,7 +224,7 @@ TEST(WebMCryptoHelpersTest, EncryptedPartitionedOddNumberOfPartitions) { ASSERT_TRUE(WebMCreateDecryptConfig(kData, sizeof(kData), kKeyId, sizeof(kKeyId), &decrypt_config, &data_offset)); - EXPECT_TRUE(decrypt_config->is_encrypted()); + EXPECT_TRUE(decrypt_config); EXPECT_EQ(std::string(kKeyId, kKeyId + sizeof(kKeyId)), decrypt_config->key_id()); EXPECT_EQ(std::string(kExpectedIv, kExpectedIv + sizeof(kExpectedIv)), @@ -254,7 +254,7 @@ TEST(WebMCryptoHelpersTest, EncryptedPartitionedZeroNumberOfPartitions) { ASSERT_TRUE(WebMCreateDecryptConfig(kData, sizeof(kData), kKeyId, sizeof(kKeyId), &decrypt_config, &data_offset)); - EXPECT_TRUE(decrypt_config->is_encrypted()); + EXPECT_TRUE(decrypt_config); EXPECT_EQ(std::string(kKeyId, kKeyId + sizeof(kKeyId)), decrypt_config->key_id()); EXPECT_EQ(std::string(kExpectedIv, kExpectedIv + sizeof(kExpectedIv)), diff --git a/chromium/media/formats/webm/webm_parser_unittest.cc b/chromium/media/formats/webm/webm_parser_unittest.cc index b24fb485046..11f3380417b 100644 --- a/chromium/media/formats/webm/webm_parser_unittest.cc +++ b/chromium/media/formats/webm/webm_parser_unittest.cc @@ -27,7 +27,7 @@ enum { kBlockCount = 5 }; class MockWebMParserClient : public WebMParserClient { public: - virtual ~MockWebMParserClient() = default; + ~MockWebMParserClient() override = default; // WebMParserClient methods. MOCK_METHOD1(OnListStart, WebMParserClient*(int)); diff --git a/chromium/media/formats/webm/webm_stream_parser_unittest.cc b/chromium/media/formats/webm/webm_stream_parser_unittest.cc index c009bb08f9f..cfc3d6fc66c 100644 --- a/chromium/media/formats/webm/webm_stream_parser_unittest.cc +++ b/chromium/media/formats/webm/webm_stream_parser_unittest.cc @@ -13,6 +13,7 @@ #include "media/base/mock_media_log.h" #include "media/base/stream_parser.h" #include "media/base/test_data_util.h" +#include "media/base/test_helpers.h" #include "media/base/text_track_config.h" #include "testing/gtest/include/gtest/gtest.h" @@ -91,7 +92,7 @@ class WebMStreamParserTest : public testing::Test { }; TEST_F(WebMStreamParserTest, VerifyMediaTrackMetadata) { - EXPECT_MEDIA_LOG(testing::HasSubstr("Estimating WebM block duration")) + EXPECT_MEDIA_LOG(WebMSimpleBlockDurationEstimatedAny()) .Times(testing::AnyNumber()); StreamParser::InitParameters params(kInfiniteDuration); params.detected_audio_track_count = 1; @@ -118,7 +119,7 @@ TEST_F(WebMStreamParserTest, VerifyMediaTrackMetadata) { } TEST_F(WebMStreamParserTest, VerifyDetectedTrack_AudioOnly) { - EXPECT_MEDIA_LOG(testing::HasSubstr("Estimating WebM block duration")) + EXPECT_MEDIA_LOG(WebMSimpleBlockDurationEstimatedAny()) .Times(testing::AnyNumber()); StreamParser::InitParameters params(kInfiniteDuration); params.detected_audio_track_count = 1; @@ -140,7 +141,7 @@ TEST_F(WebMStreamParserTest, VerifyDetectedTrack_VideoOnly) { } TEST_F(WebMStreamParserTest, VerifyDetectedTracks_AVText) { - EXPECT_MEDIA_LOG(testing::HasSubstr("Estimating WebM block duration")) + EXPECT_MEDIA_LOG(WebMSimpleBlockDurationEstimatedAny()) .Times(testing::AnyNumber()); StreamParser::InitParameters params(kInfiniteDuration); params.detected_audio_track_count = 1; @@ -153,7 +154,7 @@ TEST_F(WebMStreamParserTest, VerifyDetectedTracks_AVText) { } TEST_F(WebMStreamParserTest, ColourElement) { - EXPECT_MEDIA_LOG(testing::HasSubstr("Estimating WebM block duration")) + EXPECT_MEDIA_LOG(WebMSimpleBlockDurationEstimatedAny()) .Times(testing::AnyNumber()); StreamParser::InitParameters params(kInfiniteDuration); params.detected_audio_track_count = 0; @@ -192,4 +193,27 @@ TEST_F(WebMStreamParserTest, ColourElement) { EXPECT_EQ(mmdata.luminance_min, 30); } +TEST_F(WebMStreamParserTest, ColourElementWithUnspecifiedRange) { + EXPECT_MEDIA_LOG(WebMSimpleBlockDurationEstimatedAny()) + .Times(testing::AnyNumber()); + StreamParser::InitParameters params(kInfiniteDuration); + params.detected_audio_track_count = 0; + params.detected_video_track_count = 1; + params.detected_text_track_count = 0; + ParseWebMFile("colour_unspecified_range.webm", params); + EXPECT_EQ(media_tracks_->tracks().size(), 1u); + + const auto& video_track = media_tracks_->tracks()[0]; + EXPECT_EQ(video_track->type(), MediaTrack::Video); + + const VideoDecoderConfig& video_config = + media_tracks_->getVideoConfig(video_track->bytestream_track_id()); + + VideoColorSpace expected_color_space(VideoColorSpace::PrimaryID::SMPTEST428_1, + VideoColorSpace::TransferID::LOG, + VideoColorSpace::MatrixID::RGB, + gfx::ColorSpace::RangeID::INVALID); + EXPECT_EQ(video_config.color_space_info(), expected_color_space); +} + } // namespace media diff --git a/chromium/media/formats/webm/webm_video_client.cc b/chromium/media/formats/webm/webm_video_client.cc index 651b88f9a3d..61bc28ed979 100644 --- a/chromium/media/formats/webm/webm_video_client.cc +++ b/chromium/media/formats/webm/webm_video_client.cc @@ -6,7 +6,7 @@ #include "media/base/video_decoder_config.h" #include "media/formats/webm/webm_constants.h" -#include "third_party/libaom/av1_features.h" +#include "third_party/libaom/av1_buildflags.h" namespace media { |