diff options
Diffstat (limited to 'chromium/media/formats')
7 files changed, 268 insertions, 37 deletions
diff --git a/chromium/media/formats/BUILD.gn b/chromium/media/formats/BUILD.gn index fbb2170607d..1a9089f2b1a 100644 --- a/chromium/media/formats/BUILD.gn +++ b/chromium/media/formats/BUILD.gn @@ -45,6 +45,8 @@ source_set("formats") { "mpeg/mpeg1_audio_stream_parser.h", "mpeg/mpeg_audio_stream_parser_base.cc", "mpeg/mpeg_audio_stream_parser_base.h", + "webcodecs/webcodecs_encoded_chunk_stream_parser.cc", + "webcodecs/webcodecs_encoded_chunk_stream_parser.h", "webm/webm_audio_client.cc", "webm/webm_audio_client.h", "webm/webm_cluster_parser.cc", diff --git a/chromium/media/formats/mp4/h264_annex_b_fuzz_corpus/pps_neq_sps_config_idr.bin b/chromium/media/formats/mp4/h264_annex_b_fuzz_corpus/pps_neq_sps_config_idr.bin Binary files differnew file mode 100644 index 00000000000..77706919f14 --- /dev/null +++ b/chromium/media/formats/mp4/h264_annex_b_fuzz_corpus/pps_neq_sps_config_idr.bin diff --git a/chromium/media/formats/mp4/h264_annex_b_to_avc_bitstream_converter.cc b/chromium/media/formats/mp4/h264_annex_b_to_avc_bitstream_converter.cc index f3c4e8ef0e8..621bd8b7e49 100644 --- a/chromium/media/formats/mp4/h264_annex_b_to_avc_bitstream_converter.cc +++ b/chromium/media/formats/mp4/h264_annex_b_to_avc_bitstream_converter.cc @@ -78,7 +78,7 @@ Status H264AnnexBToAvcBitstreamConverter::ConvertChunk( } case H264NALU::kSPSExt: { - NOTREACHED() << "SPS extensions are not supported yet."; + // SPS extensions are not supported yet. break; } @@ -95,7 +95,7 @@ Status H264AnnexBToAvcBitstreamConverter::ConvertChunk( blob(nalu.data, nalu.data + nalu.size)); pps_to_include.insert(pps_id); if (auto* pps = parser_.GetPPS(pps_id)) - pps_to_include.insert(pps->seq_parameter_set_id); + sps_to_include.insert(pps->seq_parameter_set_id); config_changed = true; break; } diff --git a/chromium/media/formats/mp4/h264_annex_b_to_avc_bitstream_converter_unittest.cc b/chromium/media/formats/mp4/h264_annex_b_to_avc_bitstream_converter_unittest.cc index 8fadf60e6f2..176dc31063f 100644 --- a/chromium/media/formats/mp4/h264_annex_b_to_avc_bitstream_converter_unittest.cc +++ b/chromium/media/formats/mp4/h264_annex_b_to_avc_bitstream_converter_unittest.cc @@ -37,10 +37,11 @@ std::vector<uint8_t> ReadTestFile(std::string name) { namespace media { TEST(H264AnnexBToAvcBitstreamConverterTest, Success) { - std::string chunks[] = {"chunk1-config-idr.bin", "chunk2-non-idr.bin", - "chunk3-non-idr.bin", "chunk4-non-idr.bin", - "chunk5-non-idr.bin", "chunk6-config-idr.bin", - "chunk7-non-idr.bin"}; + std::string chunks[] = { + "chunk1-config-idr.bin", "chunk2-non-idr.bin", + "chunk3-non-idr.bin", "chunk4-non-idr.bin", + "chunk5-non-idr.bin", "chunk6-config-idr.bin", + "chunk7-non-idr.bin", "pps_neq_sps_config_idr.bin"}; H264AnnexBToAvcBitstreamConverter converter; for (std::string& name : chunks) { diff --git a/chromium/media/formats/mpeg/mpeg1_audio_stream_parser.cc b/chromium/media/formats/mpeg/mpeg1_audio_stream_parser.cc index 05a84624583..d12f7cacee4 100644 --- a/chromium/media/formats/mpeg/mpeg1_audio_stream_parser.cc +++ b/chromium/media/formats/mpeg/mpeg1_audio_stream_parser.cc @@ -12,28 +12,6 @@ namespace { constexpr uint32_t kMPEG1StartCodeMask = 0xffe00000; -// Map that determines which bitrate_index & channel_mode combinations -// are allowed. -// Derived from: http://mpgedit.org/mpgedit/mpeg_format/MP3Format.html -constexpr bool kIsAllowed[17][4] = { - {true, true, true, true}, // free - {true, false, false, false}, // 32 - {true, false, false, false}, // 48 - {true, false, false, false}, // 56 - {true, true, true, true}, // 64 - {true, false, false, false}, // 80 - {true, true, true, true}, // 96 - {true, true, true, true}, // 112 - {true, true, true, true}, // 128 - {true, true, true, true}, // 160 - {true, true, true, true}, // 192 - {false, true, true, true}, // 224 - {false, true, true, true}, // 256 - {false, true, true, true}, // 320 - {false, true, true, true}, // 384 - {false, false, false, false} // bad -}; - // Maps version and layer information in the frame header // into an index for the |kBitrateMap|. // Derived from: http://mpgedit.org/mpgedit/mpeg_format/MP3Format.html @@ -125,15 +103,8 @@ bool MPEG1AudioStreamParser::ParseHeader(MediaLog* media_log, return false; } - if (layer == kLayer2 && !kIsAllowed[bitrate_index][channel_mode]) { - if (media_log) { - LIMITED_MEDIA_LOG(DEBUG, media_log, *media_log_limit, 5) - << "Invalid MP3 (bitrate_index, channel_mode)" - << " combination :" << std::hex << " bitrate_index " << bitrate_index - << " channel_mode " << channel_mode; - } - return false; - } + // Note: For MPEG2 we don't check if a given bitrate or channel layout is + // allowed per spec since all tested decoders don't seem to care. int bitrate = kBitrateMap[bitrate_index][kVersionLayerMap[version][layer]]; diff --git a/chromium/media/formats/webcodecs/webcodecs_encoded_chunk_stream_parser.cc b/chromium/media/formats/webcodecs/webcodecs_encoded_chunk_stream_parser.cc new file mode 100644 index 00000000000..cb09be7e0bf --- /dev/null +++ b/chromium/media/formats/webcodecs/webcodecs_encoded_chunk_stream_parser.cc @@ -0,0 +1,178 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/formats/webcodecs/webcodecs_encoded_chunk_stream_parser.h" + +#include <string> + +#include "base/callback.h" +#include "base/logging.h" +#include "base/notreached.h" +#include "media/base/media_log.h" +#include "media/base/media_track.h" +#include "media/base/media_tracks.h" +#include "media/base/stream_parser_buffer.h" +#include "media/base/text_track_config.h" +#include "media/base/timestamp_constants.h" + +namespace { + +// TODO(crbug.com/1144908): Since these must be identical to those generated +// in the SourceBuffer, consider moving these to possibly stream_parser.h. +// Meanwhile, must be kept in sync with similar constexpr in SourceBuffer +// manually. +constexpr media::StreamParser::TrackId kWebCodecsAudioTrackId = 1; +constexpr media::StreamParser::TrackId kWebCodecsVideoTrackId = 2; + +} // namespace + +namespace media { + +WebCodecsEncodedChunkStreamParser::WebCodecsEncodedChunkStreamParser( + std::unique_ptr<AudioDecoderConfig> audio_config) + : state_(kWaitingForInit), audio_config_(std::move(audio_config)) { + DCHECK(audio_config_ && !video_config_); +} + +WebCodecsEncodedChunkStreamParser::WebCodecsEncodedChunkStreamParser( + std::unique_ptr<VideoDecoderConfig> video_config) + : state_(kWaitingForInit), video_config_(std::move(video_config)) { + DCHECK(video_config_ && !audio_config_); +} + +WebCodecsEncodedChunkStreamParser::~WebCodecsEncodedChunkStreamParser() = + default; + +void WebCodecsEncodedChunkStreamParser::Init( + InitCB init_cb, + const NewConfigCB& config_cb, + const NewBuffersCB& new_buffers_cb, + bool /* ignore_text_tracks */, + const EncryptedMediaInitDataCB& /* ignored */, + const NewMediaSegmentCB& new_segment_cb, + const EndMediaSegmentCB& end_of_segment_cb, + MediaLog* media_log) { + DCHECK_EQ(state_, kWaitingForInit); + DCHECK(!init_cb_); + DCHECK(init_cb); + DCHECK(config_cb); + DCHECK(new_buffers_cb); + DCHECK(new_segment_cb); + DCHECK(end_of_segment_cb); + + ChangeState(kWaitingForConfigEmission); + init_cb_ = std::move(init_cb); + config_cb_ = config_cb; + new_buffers_cb_ = new_buffers_cb; + new_segment_cb_ = new_segment_cb; + end_of_segment_cb_ = end_of_segment_cb; + media_log_ = media_log; +} + +void WebCodecsEncodedChunkStreamParser::Flush() { + DCHECK_NE(state_, kWaitingForInit); + if (state_ == kWaitingForEncodedChunks) + ChangeState(kWaitingForConfigEmission); +} + +bool WebCodecsEncodedChunkStreamParser::GetGenerateTimestampsFlag() const { + return false; +} + +bool WebCodecsEncodedChunkStreamParser::Parse(const uint8_t* /* buf */, + int /* size */) { + // TODO(crbug.com/1144908): Protect against app reaching this (and similer + // inverse case in other parsers) simply by using the wrong append method on + // the SourceBuffer. Maybe a better MEDIA_LOG here would be sufficient? Or + // instead have the top-level SourceBuffer throw synchronous exception when + // attempting the wrong append method, without causing parse/decode error? + NOTREACHED(); // ProcessChunks() is the method to use instead for this + // parser. + return false; +} + +bool WebCodecsEncodedChunkStreamParser::ProcessChunks( + std::unique_ptr<BufferQueue> buffer_queue) { + DCHECK_NE(state_, kWaitingForInit); + + if (state_ == kError) + return false; + + if (state_ == kWaitingForConfigEmission) { + // Must (still) have only one config. We'll retain ownership. + // MediaTracks::AddAudio/VideoTrack copies the config. + DCHECK((audio_config_ && !video_config_) || + (video_config_ && !audio_config_)); + auto media_tracks = std::make_unique<MediaTracks>(); + if (audio_config_) { + media_tracks->AddAudioTrack( + *audio_config_, kWebCodecsAudioTrackId, MediaTrack::Kind("main"), + MediaTrack::Label(""), MediaTrack::Language("")); + } else if (video_config_) { + media_tracks->AddVideoTrack( + *video_config_, kWebCodecsVideoTrackId, MediaTrack::Kind("main"), + MediaTrack::Label(""), MediaTrack::Language("")); + } + + if (!config_cb_.Run(std::move(media_tracks), TextTrackConfigMap())) { + ChangeState(kError); + return false; + } + + if (init_cb_) { + InitParameters params(kInfiniteDuration); + params.liveness = DemuxerStream::LIVENESS_UNKNOWN; + if (audio_config_) + params.detected_audio_track_count = 1; + if (video_config_) + params.detected_video_track_count = 1; + params.detected_text_track_count = 0; + std::move(init_cb_).Run(params); + } + + ChangeState(kWaitingForEncodedChunks); + } + + DCHECK_EQ(state_, kWaitingForEncodedChunks); + + // All of |buffer_queue| must be of the media type (audio or video) + // corresponding to the exactly one type of decoder config we have. Otherwise, + // the caller has provided encoded chunks for the wrong kind of config. + DemuxerStream::Type expected_type = + audio_config_ ? DemuxerStream::AUDIO : DemuxerStream::VIDEO; + for (const auto& it : *buffer_queue) { + if (it->type() != expected_type) { + MEDIA_LOG(ERROR, media_log_) + << "Incorrect EncodedChunk type (audio vs video) appended"; + ChangeState(kError); + return false; + } + } + + // TODO(crbug.com/1144908): Add a different new_buffers_cb type for us to use + // so that we can just std::move the buffer_queue, and avoid potential issues + // with out-of-order timestamps in the caller-provided queue that would + // otherwise cause parse failure in MergeBufferQueues with the current, legacy + // style of new_buffers_cb that depends on parsers to emit sanely time-ordered + // groups of frames from *muxed* multi-track bytestreams. FrameProcessor is + // capable of handling our buffer_queue verbatim. + BufferQueueMap buffers; + if (audio_config_) + buffers.insert(std::make_pair(kWebCodecsAudioTrackId, *buffer_queue)); + else + buffers.insert(std::make_pair(kWebCodecsVideoTrackId, *buffer_queue)); + new_segment_cb_.Run(); + if (!new_buffers_cb_.Run(buffers)) + return false; + end_of_segment_cb_.Run(); + + return true; +} + +void WebCodecsEncodedChunkStreamParser::ChangeState(State new_state) { + DVLOG(1) << __func__ << ": " << state_ << " -> " << new_state; + state_ = new_state; +} + +} // namespace media diff --git a/chromium/media/formats/webcodecs/webcodecs_encoded_chunk_stream_parser.h b/chromium/media/formats/webcodecs/webcodecs_encoded_chunk_stream_parser.h new file mode 100644 index 00000000000..c5dafee217a --- /dev/null +++ b/chromium/media/formats/webcodecs/webcodecs_encoded_chunk_stream_parser.h @@ -0,0 +1,79 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_FORMATS_WEBCODECS_WEBCODECS_ENCODED_CHUNK_STREAM_PARSER_H_ +#define MEDIA_FORMATS_WEBCODECS_WEBCODECS_ENCODED_CHUNK_STREAM_PARSER_H_ + +#include <stdint.h> + +#include <memory> + +#include "base/callback_forward.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "media/base/audio_decoder_config.h" +#include "media/base/media_export.h" +#include "media/base/stream_parser.h" +#include "media/base/video_decoder_config.h" + +namespace media { + +class MEDIA_EXPORT WebCodecsEncodedChunkStreamParser : public StreamParser { + public: + explicit WebCodecsEncodedChunkStreamParser( + std::unique_ptr<AudioDecoderConfig> audio_config); + explicit WebCodecsEncodedChunkStreamParser( + std::unique_ptr<VideoDecoderConfig> video_config); + ~WebCodecsEncodedChunkStreamParser() override; + + // StreamParser implementation. + void Init(InitCB init_cb, + const NewConfigCB& config_cb, + const NewBuffersCB& new_buffers_cb, + bool ignore_text_tracks /* must be true */, + const EncryptedMediaInitDataCB& encrypted_media_init_data_cb, + const NewMediaSegmentCB& new_segment_cb, + const EndMediaSegmentCB& end_of_segment_cb, + MediaLog* media_log) override; + void Flush() override; + bool GetGenerateTimestampsFlag() const override; + bool Parse(const uint8_t* buf, int size) override; + + // Processes and emits buffers from |buffer_queue|. If state is + // kWaitingForConfigEmission, first emit the config. + bool ProcessChunks(std::unique_ptr<BufferQueue> buffer_queue) override; + + private: + enum State { + kWaitingForInit, + kWaitingForConfigEmission, + kWaitingForEncodedChunks, + kError + }; + + void ChangeState(State new_state); + + State state_; + + // These configs are populated during ctor. A copy of the appropriate config + // is emitted on demand when "parsing" newly appended encoded chunks if that + // append occurs when state is kWaitingForConfigEmission. Note, only one type + // of config can be emitted (not both), for an instance of this parser. + std::unique_ptr<AudioDecoderConfig> audio_config_; + std::unique_ptr<VideoDecoderConfig> video_config_; + + InitCB init_cb_; + NewConfigCB config_cb_; + NewBuffersCB new_buffers_cb_; + + NewMediaSegmentCB new_segment_cb_; + EndMediaSegmentCB end_of_segment_cb_; + MediaLog* media_log_; + + DISALLOW_COPY_AND_ASSIGN(WebCodecsEncodedChunkStreamParser); +}; + +} // namespace media + +#endif // MEDIA_FORMATS_WEBCODECS_WEBCODECS_ENCODED_CHUNK_STREAM_PARSER_H_ |