diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn index 0e4bebc9f56321..6d3763746da368 100644 --- a/media/base/BUILD.gn +++ b/media/base/BUILD.gn @@ -135,6 +135,10 @@ source_set("base") { "media_resources.h", "media_switches.cc", "media_switches.h", + "media_track.cc", + "media_track.h", + "media_tracks.cc", + "media_tracks.h", "media_util.cc", "media_util.h", "mime_util.cc", diff --git a/media/base/media_track.cc b/media/base/media_track.cc new file mode 100644 index 00000000000000..ad5178f2b029a9 --- /dev/null +++ b/media/base/media_track.cc @@ -0,0 +1,18 @@ +// Copyright 2016 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/base/media_track.h" + +namespace media { + +MediaTrack::MediaTrack(Type type, + const std::string& id, + const std::string& kind, + const std::string& label, + const std::string& lang) + : type_(type), id_(id), kind_(kind), label_(label), language_(lang) {} + +MediaTrack::~MediaTrack() {} + +} // namespace media diff --git a/media/base/media_track.h b/media/base/media_track.h new file mode 100644 index 00000000000000..a5cb6d3d81817b --- /dev/null +++ b/media/base/media_track.h @@ -0,0 +1,41 @@ +// Copyright 2016 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_BASE_MEDIA_TRACK_H_ +#define MEDIA_BASE_MEDIA_TRACK_H_ + +#include + +#include "media/base/media_export.h" + +namespace media { + +class MEDIA_EXPORT MediaTrack { + public: + enum Type { Text, Audio, Video }; + MediaTrack(Type type, + const std::string& id, + const std::string& kind, + const std::string& label, + const std::string& lang); + ~MediaTrack(); + + Type type() const { return type_; } + + const std::string& id() const { return id_; } + const std::string& kind() const { return kind_; } + const std::string& label() const { return label_; } + const std::string& language() const { return language_; } + + private: + Type type_; + std::string id_; + std::string kind_; + std::string label_; + std::string language_; +}; + +} // namespace media + +#endif // MEDIA_BASE_MEDIA_TRACK_H_ diff --git a/media/base/media_tracks.cc b/media/base/media_tracks.cc new file mode 100644 index 00000000000000..832e5a822b12a4 --- /dev/null +++ b/media/base/media_tracks.cc @@ -0,0 +1,81 @@ +// Copyright 2016 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/base/media_tracks.h" + +#include "base/bind.h" +#include "media/base/audio_decoder_config.h" +#include "media/base/video_decoder_config.h" + +namespace media { + +MediaTracks::MediaTracks() {} + +MediaTracks::~MediaTracks() {} + +void MediaTracks::AddAudioTrack(const AudioDecoderConfig& config, + const std::string& id, + const std::string& kind, + const std::string& label, + const std::string& language) { + DCHECK(config.IsValidConfig()); + CHECK(audio_configs_.find(id) == audio_configs_.end()); + scoped_ptr track = make_scoped_ptr( + new MediaTrack(MediaTrack::Audio, id, kind, label, language)); + tracks_.push_back(std::move(track)); + audio_configs_[id] = config; +} + +void MediaTracks::AddVideoTrack(const VideoDecoderConfig& config, + const std::string& id, + const std::string& kind, + const std::string& label, + const std::string& language) { + DCHECK(config.IsValidConfig()); + CHECK(video_configs_.find(id) == video_configs_.end()); + scoped_ptr track = make_scoped_ptr( + new MediaTrack(MediaTrack::Video, id, kind, label, language)); + tracks_.push_back(std::move(track)); + video_configs_[id] = config; +} + +const AudioDecoderConfig& MediaTracks::getAudioConfig( + const std::string& id) const { + auto it = audio_configs_.find(id); + if (it != audio_configs_.end()) + return it->second; + static AudioDecoderConfig invalidConfig; + return invalidConfig; +} + +const VideoDecoderConfig& MediaTracks::getVideoConfig( + const std::string& id) const { + auto it = video_configs_.find(id); + if (it != video_configs_.end()) + return it->second; + static VideoDecoderConfig invalidConfig; + return invalidConfig; +} + +const AudioDecoderConfig& MediaTracks::getFirstAudioConfig() const { + for (const auto& track : tracks()) { + if (track->type() == MediaTrack::Audio) { + return getAudioConfig(track->id()); + } + } + static AudioDecoderConfig invalidConfig; + return invalidConfig; +} + +const VideoDecoderConfig& MediaTracks::getFirstVideoConfig() const { + for (const auto& track : tracks()) { + if (track->type() == MediaTrack::Video) { + return getVideoConfig(track->id()); + } + } + static VideoDecoderConfig invalidConfig; + return invalidConfig; +} + +} // namespace media diff --git a/media/base/media_tracks.h b/media/base/media_tracks.h new file mode 100644 index 00000000000000..4e0fbb0fc1f881 --- /dev/null +++ b/media/base/media_tracks.h @@ -0,0 +1,62 @@ +// Copyright 2016 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_BASE_MEDIA_TRACKS_H_ +#define MEDIA_BASE_MEDIA_TRACKS_H_ + +#include +#include +#include + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "media/base/media_export.h" +#include "media/base/media_track.h" + +namespace media { + +class AudioDecoderConfig; +class VideoDecoderConfig; + +class MEDIA_EXPORT MediaTracks { + public: + typedef std::vector> MediaTracksCollection; + + MediaTracks(); + ~MediaTracks(); + + // Callers need to ensure that track id is unique. + void AddAudioTrack(const AudioDecoderConfig& config, + const std::string& id, + const std::string& kind, + const std::string& label, + const std::string& language); + // Callers need to ensure that track id is unique. + void AddVideoTrack(const VideoDecoderConfig& config, + const std::string& id, + const std::string& kind, + const std::string& label, + const std::string& language); + + const MediaTracksCollection& tracks() const { return tracks_; } + + const AudioDecoderConfig& getAudioConfig(const std::string& id) const; + const VideoDecoderConfig& getVideoConfig(const std::string& id) const; + + // TODO(servolk): These are temporary helpers useful until all code paths are + // converted to properly handle multiple media tracks. + const AudioDecoderConfig& getFirstAudioConfig() const; + const VideoDecoderConfig& getFirstVideoConfig() const; + + private: + MediaTracksCollection tracks_; + std::map audio_configs_; + std::map video_configs_; + + DISALLOW_COPY_AND_ASSIGN(MediaTracks); +}; + +} // namespace media + +#endif // MEDIA_BASE_MEDIA_TRACKS_H_ diff --git a/media/base/stream_parser.h b/media/base/stream_parser.h index 11740c9d1c6eeb..4b9fa7f3e4d314 100644 --- a/media/base/stream_parser.h +++ b/media/base/stream_parser.h @@ -25,10 +25,9 @@ namespace media { -class AudioDecoderConfig; +class MediaTracks; class StreamParserBuffer; class TextTrackConfig; -class VideoDecoderConfig; // Abstract interface for parsing media byte streams. class MEDIA_EXPORT StreamParser { @@ -76,18 +75,17 @@ class MEDIA_EXPORT StreamParser { typedef base::Callback InitCB; // Indicates when new stream configurations have been parsed. - // First parameter - The new audio configuration. If the config is not valid - // then it means that there isn't an audio stream. - // Second parameter - The new video configuration. If the config is not valid - // then it means that there isn't an audio stream. - // Third parameter - The new text tracks configuration. If the map is empty, - // then no text tracks were parsed from the stream. + // First parameter - An object containing information about media tracks as + // well as audio/video decoder configs associated with each + // track. + // Second parameter - The new text tracks configuration. If the map is empty, + // then no text tracks were parsed from the stream. // Return value - True if the new configurations are accepted. // False if the new configurations are not supported // and indicates that a parsing error should be signalled. - typedef base::Callback NewConfigCB; + typedef base::Callback, + const TextTrackConfigMap&)> + NewConfigCB; // New stream buffers have been parsed. // First parameter - A queue of newly parsed audio buffers. diff --git a/media/blink/websourcebuffer_impl.cc b/media/blink/websourcebuffer_impl.cc index ffb62c5c539791..ea09bde707094c 100644 --- a/media/blink/websourcebuffer_impl.cc +++ b/media/blink/websourcebuffer_impl.cc @@ -12,6 +12,7 @@ #include "base/bind.h" #include "base/callback.h" #include "base/callback_helpers.h" +#include "media/base/media_tracks.h" #include "media/base/timestamp_constants.h" #include "media/filters/chunk_demuxer.h" #include "third_party/WebKit/public/platform/WebSourceBufferClient.h" @@ -158,8 +159,10 @@ void WebSourceBufferImpl::removedFromMediaSource() { client_ = NULL; } -void WebSourceBufferImpl::InitSegmentReceived() { +void WebSourceBufferImpl::InitSegmentReceived(const MediaTracks& tracks) { DVLOG(1) << __FUNCTION__; + // TODO(servolk): Implement passing MediaTrack info to blink level. + // https://crbug.com/249428 client_->initializationSegmentReceived(); } diff --git a/media/blink/websourcebuffer_impl.h b/media/blink/websourcebuffer_impl.h index 9111fd27513c81..1dc54e6f2a1497 100644 --- a/media/blink/websourcebuffer_impl.h +++ b/media/blink/websourcebuffer_impl.h @@ -16,6 +16,7 @@ namespace media { class ChunkDemuxer; +class MediaTracks; class WebSourceBufferImpl : public blink::WebSourceBuffer { public: @@ -42,7 +43,7 @@ class WebSourceBufferImpl : public blink::WebSourceBuffer { private: // Demuxer callback handler to process an initialization segment received // during an append() call. - void InitSegmentReceived(); + void InitSegmentReceived(const MediaTracks& tracks); std::string id_; ChunkDemuxer* demuxer_; // Owned by WebMediaPlayerImpl. diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc index c095f5a292cb8d..bd2a87e5a25c76 100644 --- a/media/filters/chunk_demuxer_unittest.cc +++ b/media/filters/chunk_demuxer_unittest.cc @@ -18,6 +18,7 @@ #include "media/base/audio_decoder_config.h" #include "media/base/decoder_buffer.h" #include "media/base/decrypt_config.h" +#include "media/base/media_tracks.h" #include "media/base/mock_demuxer_host.h" #include "media/base/mock_media_log.h" #include "media/base/test_data_util.h" @@ -841,7 +842,7 @@ class ChunkDemuxerTest : public ::testing::Test { // it. if (stream_flags != 0) { ExpectInitMediaLogs(stream_flags); - EXPECT_CALL(*this, InitSegmentReceived()); + EXPECT_CALL(*this, InitSegmentReceived(_)); } else { // OnNewConfigs() requires at least one audio, video, or text track. EXPECT_MEDIA_LOG(StreamParsingFailed()); @@ -883,11 +884,11 @@ class ChunkDemuxerTest : public ::testing::Test { // incompatible with InSequence tests. Refactoring of the duration // set expectation to not be added during CreateInitDoneCB() could fix this. ExpectInitMediaLogs(audio_flags); - EXPECT_CALL(*this, InitSegmentReceived()); + EXPECT_CALL(*this, InitSegmentReceived(_)); AppendInitSegmentWithSourceId(audio_id, audio_flags); ExpectInitMediaLogs(video_flags); - EXPECT_CALL(*this, InitSegmentReceived()); + EXPECT_CALL(*this, InitSegmentReceived(_)); AppendInitSegmentWithSourceId(video_id, video_flags); return true; } @@ -923,7 +924,7 @@ class ChunkDemuxerTest : public ::testing::Test { // Adding expectation prior to CreateInitDoneCB() here because InSequence // tests require init segment received before duration set. ExpectInitMediaLogs(HAS_AUDIO | HAS_VIDEO); - EXPECT_CALL(*this, InitSegmentReceived()); + EXPECT_CALL(*this, InitSegmentReceived(_)); demuxer_->Initialize( &host_, CreateInitDoneCB(base::TimeDelta::FromMilliseconds(2744), PIPELINE_OK), true); @@ -949,7 +950,7 @@ class ChunkDemuxerTest : public ::testing::Test { // media/test/data/bear-320x240-manifest.js which were // generated from media/test/data/bear-640x360.webm and // media/test/data/bear-320x240.webm respectively. - EXPECT_CALL(*this, InitSegmentReceived()); + EXPECT_CALL(*this, InitSegmentReceived(_)); AppendData(bear2->data(), 4340); // Append a media segment that goes from [0.527000, 1.014000). @@ -960,7 +961,7 @@ class ChunkDemuxerTest : public ::testing::Test { // Append initialization segment for bear1 & fill gap with [779-1197) // segment. - EXPECT_CALL(*this, InitSegmentReceived()); + EXPECT_CALL(*this, InitSegmentReceived(_)); AppendData(bear1->data(), 4370); EXPECT_MEDIA_LOG(WebMSimpleBlockDurationEstimated(23)); EXPECT_MEDIA_LOG(GeneratedSplice(26000, 779000)); @@ -1308,7 +1309,7 @@ class ChunkDemuxerTest : public ::testing::Test { // Read a WebM file into memory and send the data to the demuxer. scoped_refptr buffer = ReadTestDataFile(filename); - EXPECT_CALL(*this, InitSegmentReceived()); + EXPECT_CALL(*this, InitSegmentReceived(_)); AppendDataInPieces(buffer->data(), buffer->data_size(), 512); // Verify that the timestamps on the first few packets match what we @@ -1345,7 +1346,7 @@ class ChunkDemuxerTest : public ::testing::Test { void(EmeInitDataType init_data_type, const std::vector& init_data)); - MOCK_METHOD0(InitSegmentReceived, void(void)); + MOCK_METHOD1(InitSegmentReceived, void(const MediaTracks&)); void Seek(base::TimeDelta seek_time) { demuxer_->StartWaitingForSeek(seek_time); @@ -1547,7 +1548,7 @@ TEST_F(ChunkDemuxerTest, SingleTextTrackIdChange) { CreateInitSegmentWithAlternateTextTrackNum(HAS_TEXT | HAS_AUDIO | HAS_VIDEO, false, false, &info_tracks, &info_tracks_size); - EXPECT_CALL(*this, InitSegmentReceived()); + EXPECT_CALL(*this, InitSegmentReceived(_)); demuxer_->AppendData(kSourceId, info_tracks.get(), info_tracks_size, append_window_start_for_next_append_, append_window_end_for_next_append_, @@ -1592,7 +1593,7 @@ TEST_F(ChunkDemuxerTest, InitSegmentSetsNeedRandomAccessPointFlag) { MuxedStreamInfo(kTextTrackNum, "25K 40K")); CheckExpectedRanges("{ [23,46) }"); - EXPECT_CALL(*this, InitSegmentReceived()); + EXPECT_CALL(*this, InitSegmentReceived(_)); AppendInitSegment(HAS_TEXT | HAS_AUDIO | HAS_VIDEO); AppendMuxedCluster(MuxedStreamInfo(kAudioTrackNum, "46K 69K", 23), MuxedStreamInfo(kVideoTrackNum, "60 90K", 30), @@ -1616,7 +1617,7 @@ TEST_F(ChunkDemuxerTest, Shutdown_BeforeAllInitSegmentsAppended) { EXPECT_EQ(AddId("video", HAS_VIDEO), ChunkDemuxer::kOk); ExpectInitMediaLogs(HAS_AUDIO); - EXPECT_CALL(*this, InitSegmentReceived()); + EXPECT_CALL(*this, InitSegmentReceived(_)); AppendInitSegmentWithSourceId("audio", HAS_AUDIO); ShutdownDemuxer(); @@ -1635,7 +1636,7 @@ TEST_F(ChunkDemuxerTest, Shutdown_BeforeAllInitSegmentsAppendedText) { .Times(Exactly(1)); ExpectInitMediaLogs(HAS_VIDEO); - EXPECT_CALL(*this, InitSegmentReceived()); + EXPECT_CALL(*this, InitSegmentReceived(_)); AppendInitSegmentWithSourceId("video_and_text", HAS_VIDEO | HAS_TEXT); ShutdownDemuxer(); @@ -2157,7 +2158,7 @@ TEST_F(ChunkDemuxerTest, AppendingInPieces) { dst += cluster_b->size(); ExpectInitMediaLogs(HAS_AUDIO | HAS_VIDEO); - EXPECT_CALL(*this, InitSegmentReceived()); + EXPECT_CALL(*this, InitSegmentReceived(_)); AppendDataInPieces(buffer.get(), buffer_size); GenerateExpectedReads(0, 9); @@ -2412,7 +2413,7 @@ TEST_F(ChunkDemuxerTest, MultipleHeaders) { AppendCluster(kDefaultFirstCluster()); // Append another identical initialization segment. - EXPECT_CALL(*this, InitSegmentReceived()); + EXPECT_CALL(*this, InitSegmentReceived(_)); AppendInitSegment(HAS_AUDIO | HAS_VIDEO); AppendCluster(kDefaultSecondCluster()); @@ -2468,7 +2469,7 @@ TEST_F(ChunkDemuxerTest, AddIdFailures) { ASSERT_EQ(AddId(), ChunkDemuxer::kReachedIdLimit); ExpectInitMediaLogs(HAS_AUDIO); - EXPECT_CALL(*this, InitSegmentReceived()); + EXPECT_CALL(*this, InitSegmentReceived(_)); AppendInitSegmentWithSourceId(audio_id, HAS_AUDIO); // Adding an id after append should fail. @@ -2712,7 +2713,7 @@ TEST_F(ChunkDemuxerTest, GetBufferedRanges_AudioIdOnly) { ASSERT_EQ(AddId(kSourceId, HAS_AUDIO), ChunkDemuxer::kOk); ExpectInitMediaLogs(HAS_AUDIO); - EXPECT_CALL(*this, InitSegmentReceived()); + EXPECT_CALL(*this, InitSegmentReceived(_)); AppendInitSegment(HAS_AUDIO); // Test a simple cluster. @@ -2736,7 +2737,7 @@ TEST_F(ChunkDemuxerTest, GetBufferedRanges_VideoIdOnly) { ASSERT_EQ(AddId(kSourceId, HAS_VIDEO), ChunkDemuxer::kOk); ExpectInitMediaLogs(HAS_VIDEO); - EXPECT_CALL(*this, InitSegmentReceived()); + EXPECT_CALL(*this, InitSegmentReceived(_)); AppendInitSegment(HAS_VIDEO); // Test a simple cluster. @@ -3406,7 +3407,7 @@ TEST_F(ChunkDemuxerTest, EmitBuffersDuringAbort) { // PTS: 353788 (0x000565fc) [= 90 kHz-Timestamp: 0:00:03.9309] scoped_refptr buffer = ReadTestDataFile("bear-1280x720.ts"); - EXPECT_CALL(*this, InitSegmentReceived()); + EXPECT_CALL(*this, InitSegmentReceived(_)); AppendData(kSourceId, buffer->data(), buffer->data_size()); // Confirm we're in the middle of parsing a media segment. @@ -3454,7 +3455,7 @@ TEST_F(ChunkDemuxerTest, SeekCompleteDuringAbort) { // PTS: 353788 (0x000565fc) [= 90 kHz-Timestamp: 0:00:03.9309] scoped_refptr buffer = ReadTestDataFile("bear-1280x720.ts"); - EXPECT_CALL(*this, InitSegmentReceived()); + EXPECT_CALL(*this, InitSegmentReceived(_)); AppendData(kSourceId, buffer->data(), buffer->data_size()); // Confirm we're in the middle of parsing a media segment. @@ -4065,7 +4066,7 @@ TEST_F(ChunkDemuxerTest, AppendWindow_WebMFile_AudioOnly) { scoped_refptr buffer = ReadTestDataFile("bear-320x240-audio-only.webm"); ExpectInitMediaLogs(HAS_AUDIO); - EXPECT_CALL(*this, InitSegmentReceived()); + EXPECT_CALL(*this, InitSegmentReceived(_)); EXPECT_MEDIA_LOG(WebMSimpleBlockDurationEstimated(2)); AppendDataInPieces(buffer->data(), buffer->data_size(), 128); @@ -4092,7 +4093,7 @@ TEST_F(ChunkDemuxerTest, AppendWindow_AudioConfigUpdateRemovesPreroll) { scoped_refptr buffer = ReadTestDataFile("bear-320x240-audio-only.webm"); ExpectInitMediaLogs(HAS_AUDIO); - EXPECT_CALL(*this, InitSegmentReceived()); + EXPECT_CALL(*this, InitSegmentReceived(_)); EXPECT_MEDIA_LOG(WebMSimpleBlockDurationEstimated(2)); AppendDataInPieces(buffer->data(), buffer->data_size(), 512); CheckExpectedRanges("{ }"); @@ -4103,7 +4104,7 @@ TEST_F(ChunkDemuxerTest, AppendWindow_AudioConfigUpdateRemovesPreroll) { // Read a second WebM with a different config in and append the data. scoped_refptr buffer2 = ReadTestDataFile("bear-320x240-audio-only-48khz.webm"); - EXPECT_CALL(*this, InitSegmentReceived()); + EXPECT_CALL(*this, InitSegmentReceived(_)); EXPECT_MEDIA_LOG(WebMSimpleBlockDurationEstimated(21)); EXPECT_CALL(host_, SetDuration(_)).Times(AnyNumber()); ASSERT_TRUE(SetTimestampOffset(kSourceId, duration_1)); diff --git a/media/filters/media_source_state.cc b/media/filters/media_source_state.cc index ede96052668fb0..8f2f87c77b5e83 100644 --- a/media/filters/media_source_state.cc +++ b/media/filters/media_source_state.cc @@ -6,6 +6,8 @@ #include "base/callback_helpers.h" #include "base/stl_util.h" +#include "media/base/media_track.h" +#include "media/base/media_tracks.h" #include "media/filters/chunk_demuxer.h" #include "media/filters/frame_processor.h" #include "media/filters/source_buffer_stream.h" @@ -468,9 +470,13 @@ bool MediaSourceState::IsSeekWaitingForData() const { bool MediaSourceState::OnNewConfigs( bool allow_audio, bool allow_video, - const AudioDecoderConfig& audio_config, - const VideoDecoderConfig& video_config, + scoped_ptr tracks, const StreamParser::TextTrackConfigMap& text_configs) { + DCHECK(tracks.get()); + media_tracks_ = std::move(tracks); + const AudioDecoderConfig& audio_config = media_tracks_->getFirstAudioConfig(); + const VideoDecoderConfig& video_config = media_tracks_->getFirstVideoConfig(); + DVLOG(1) << "OnNewConfigs(" << allow_audio << ", " << allow_video << ", " << audio_config.IsValidConfig() << ", " << video_config.IsValidConfig() << ")"; @@ -638,7 +644,7 @@ bool MediaSourceState::OnNewConfigs( DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed"); if (success) - init_segment_received_cb_.Run(); + init_segment_received_cb_.Run(*media_tracks_); return success; } diff --git a/media/filters/media_source_state.h b/media/filters/media_source_state.h index 1a8e42adb409f3..1197015e258711 100644 --- a/media/filters/media_source_state.h +++ b/media/filters/media_source_state.h @@ -28,7 +28,7 @@ class MEDIA_EXPORT MediaSourceState { typedef base::Callback CreateDemuxerStreamCB; - typedef base::Closure InitSegmentReceivedCB; + typedef base::Callback InitSegmentReceivedCB; typedef base::Callback NewTextTrackCB; @@ -124,8 +124,7 @@ class MEDIA_EXPORT MediaSourceState { // processing decoder configurations. bool OnNewConfigs(bool allow_audio, bool allow_video, - const AudioDecoderConfig& audio_config, - const VideoDecoderConfig& video_config, + scoped_ptr tracks, const StreamParser::TextTrackConfigMap& text_configs); // Called by the |stream_parser_| at the beginning of a new media segment. @@ -183,6 +182,8 @@ class MEDIA_EXPORT MediaSourceState { // The object used to parse appended data. scoped_ptr stream_parser_; + scoped_ptr media_tracks_; + ChunkDemuxerStream* audio_; // Not owned by |this|. ChunkDemuxerStream* video_; // Not owned by |this|. diff --git a/media/formats/common/stream_parser_test_base.cc b/media/formats/common/stream_parser_test_base.cc index de80bac73f872c..b42173f087f01c 100644 --- a/media/formats/common/stream_parser_test_base.cc +++ b/media/formats/common/stream_parser_test_base.cc @@ -7,6 +7,8 @@ #include #include "base/bind.h" +#include "media/base/media_track.h" +#include "media/base/media_tracks.h" #include "media/base/test_data_util.h" #include "testing/gtest/include/gtest/gtest.h" @@ -83,14 +85,13 @@ void StreamParserTestBase::OnInitDone( } bool StreamParserTestBase::OnNewConfig( - const AudioDecoderConfig& audio_config, - const VideoDecoderConfig& video_config, + scoped_ptr tracks, const StreamParser::TextTrackConfigMap& text_config) { - DVLOG(1) << __FUNCTION__ << "(" << audio_config.IsValidConfig() << ", " - << video_config.IsValidConfig() << ")"; - EXPECT_TRUE(audio_config.IsValidConfig()); - EXPECT_FALSE(video_config.IsValidConfig()); - last_audio_config_ = audio_config; + DVLOG(1) << __FUNCTION__ << " media tracks count=" << tracks->tracks().size(); + EXPECT_EQ(tracks->tracks().size(), 1u); + EXPECT_TRUE(tracks->getFirstAudioConfig().IsValidConfig()); + EXPECT_FALSE(tracks->getFirstVideoConfig().IsValidConfig()); + last_audio_config_ = tracks->getFirstAudioConfig(); return true; } diff --git a/media/formats/common/stream_parser_test_base.h b/media/formats/common/stream_parser_test_base.h index 42cb8d1bc7dbe4..bdbfe7a0d22065 100644 --- a/media/formats/common/stream_parser_test_base.h +++ b/media/formats/common/stream_parser_test_base.h @@ -57,8 +57,7 @@ class StreamParserTestBase { size_t length, size_t piece_size); void OnInitDone(const StreamParser::InitParameters& params); - bool OnNewConfig(const AudioDecoderConfig& audio_config, - const VideoDecoderConfig& video_config, + bool OnNewConfig(scoped_ptr tracks, const StreamParser::TextTrackConfigMap& text_config); bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers, const StreamParser::BufferQueue& video_buffers, diff --git a/media/formats/mp2t/mp2t_stream_parser.cc b/media/formats/mp2t/mp2t_stream_parser.cc index 12c8a82d4b6230..90a2b96e887fe9 100644 --- a/media/formats/mp2t/mp2t_stream_parser.cc +++ b/media/formats/mp2t/mp2t_stream_parser.cc @@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "base/stl_util.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" @@ -502,6 +503,21 @@ void Mp2tStreamParser::OnAudioConfigChanged( } } +scoped_ptr GenerateMediaTrackInfo( + const AudioDecoderConfig& audio_config, + const VideoDecoderConfig& video_config) { + scoped_ptr media_tracks(new MediaTracks()); + // TODO(servolk): Implement proper sourcing of media track info as described + // in crbug.com/590085 + if (audio_config.IsValidConfig()) { + media_tracks->AddAudioTrack(audio_config, "audio", "main", "", ""); + } + if (video_config.IsValidConfig()) { + media_tracks->AddVideoTrack(video_config, "video", "main", "", ""); + } + return media_tracks; +} + bool Mp2tStreamParser::FinishInitializationIfNeeded() { // Nothing to be done if already initialized. if (is_initialized_) @@ -521,9 +537,9 @@ bool Mp2tStreamParser::FinishInitializationIfNeeded() { return true; // Pass the config before invoking the initialization callback. - RCHECK(config_cb_.Run(queue_with_config.audio_config, - queue_with_config.video_config, - TextTrackConfigMap())); + scoped_ptr media_tracks = GenerateMediaTrackInfo( + queue_with_config.audio_config, queue_with_config.video_config); + RCHECK(config_cb_.Run(std::move(media_tracks), TextTrackConfigMap())); queue_with_config.is_config_sent = true; // For Mpeg2 TS, the duration is not known. @@ -620,9 +636,9 @@ bool Mp2tStreamParser::EmitRemainingBuffers() { // Update the audio and video config if needed. BufferQueueWithConfig& queue_with_config = buffer_queue_chain_.front(); if (!queue_with_config.is_config_sent) { - if (!config_cb_.Run(queue_with_config.audio_config, - queue_with_config.video_config, - TextTrackConfigMap())) + scoped_ptr media_tracks = GenerateMediaTrackInfo( + queue_with_config.audio_config, queue_with_config.video_config); + if (!config_cb_.Run(std::move(media_tracks), TextTrackConfigMap())) return false; queue_with_config.is_config_sent = true; } diff --git a/media/formats/mp2t/mp2t_stream_parser_unittest.cc b/media/formats/mp2t/mp2t_stream_parser_unittest.cc index ab1d2306290c56..553f0c46ba37e9 100644 --- a/media/formats/mp2t/mp2t_stream_parser_unittest.cc +++ b/media/formats/mp2t/mp2t_stream_parser_unittest.cc @@ -15,6 +15,8 @@ #include "base/time/time.h" #include "media/base/audio_decoder_config.h" #include "media/base/decoder_buffer.h" +#include "media/base/media_track.h" +#include "media/base/media_tracks.h" #include "media/base/stream_parser_buffer.h" #include "media/base/test_data_util.h" #include "media/base/text_track_config.h" @@ -111,10 +113,12 @@ class Mp2tStreamParserTest : public testing::Test { << ", autoTimestampOffset=" << params.auto_update_timestamp_offset; } - bool OnNewConfig(const AudioDecoderConfig& ac, - const VideoDecoderConfig& vc, + bool OnNewConfig(scoped_ptr tracks, const StreamParser::TextTrackConfigMap& tc) { - DVLOG(1) << "OnNewConfig: audio=" << ac.IsValidConfig() + const AudioDecoderConfig& ac = tracks->getFirstAudioConfig(); + const VideoDecoderConfig& vc = tracks->getFirstVideoConfig(); + DVLOG(1) << "OnNewConfig: media tracks count=" << tracks->tracks().size() + << ", audio=" << ac.IsValidConfig() << ", video=" << vc.IsValidConfig(); config_count_++; EXPECT_TRUE(ac.IsValidConfig()); diff --git a/media/formats/mp4/mp4_stream_parser.cc b/media/formats/mp4/mp4_stream_parser.cc index 7becdf941019ff..95abf83d786557 100644 --- a/media/formats/mp4/mp4_stream_parser.cc +++ b/media/formats/mp4/mp4_stream_parser.cc @@ -14,6 +14,7 @@ #include "base/time/time.h" #include "build/build_config.h" #include "media/base/audio_decoder_config.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" @@ -353,7 +354,16 @@ bool MP4StreamParser::ParseMoov(BoxReader* reader) { if (!moov_->pssh.empty()) OnEncryptedMediaInitData(moov_->pssh); - RCHECK(config_cb_.Run(audio_config, video_config, TextTrackConfigMap())); + scoped_ptr media_tracks(new MediaTracks()); + // TODO(servolk): Implement proper sourcing of media track info as described + // in crbug.com/590085 + if (audio_config.IsValidConfig()) { + media_tracks->AddAudioTrack(audio_config, "audio", "", "", ""); + } + if (video_config.IsValidConfig()) { + media_tracks->AddVideoTrack(video_config, "video", "", "", ""); + } + RCHECK(config_cb_.Run(std::move(media_tracks), TextTrackConfigMap())); StreamParser::InitParameters params(kInfiniteDuration()); if (moov_->extends.header.fragment_duration > 0) { diff --git a/media/formats/mp4/mp4_stream_parser_unittest.cc b/media/formats/mp4/mp4_stream_parser_unittest.cc index 635acd1bdbf0cb..1fd2b7533b3579 100644 --- a/media/formats/mp4/mp4_stream_parser_unittest.cc +++ b/media/formats/mp4/mp4_stream_parser_unittest.cc @@ -15,6 +15,8 @@ #include "base/time/time.h" #include "media/base/audio_decoder_config.h" #include "media/base/decoder_buffer.h" +#include "media/base/media_track.h" +#include "media/base/media_tracks.h" #include "media/base/mock_media_log.h" #include "media/base/stream_parser_buffer.h" #include "media/base/test_data_util.h" @@ -97,14 +99,14 @@ class MP4StreamParserTest : public testing::Test { EXPECT_EQ(expected_liveness, params.liveness); } - bool NewConfigF(const AudioDecoderConfig& ac, - const VideoDecoderConfig& vc, + bool NewConfigF(scoped_ptr tracks, const StreamParser::TextTrackConfigMap& tc) { - DVLOG(1) << "NewConfigF: audio=" << ac.IsValidConfig() - << ", video=" << vc.IsValidConfig(); configs_received_ = true; - audio_decoder_config_ = ac; - video_decoder_config_ = vc; + audio_decoder_config_ = tracks->getFirstAudioConfig(); + video_decoder_config_ = tracks->getFirstVideoConfig(); + DVLOG(1) << "NewConfigF: track count=" << tracks->tracks().size() + << " audio=" << audio_decoder_config_.IsValidConfig() + << " video=" << video_decoder_config_.IsValidConfig(); return true; } diff --git a/media/formats/mpeg/mpeg_audio_stream_parser_base.cc b/media/formats/mpeg/mpeg_audio_stream_parser_base.cc index ea2261fad7965e..202849527de0b1 100644 --- a/media/formats/mpeg/mpeg_audio_stream_parser_base.cc +++ b/media/formats/mpeg/mpeg_audio_stream_parser_base.cc @@ -7,6 +7,7 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "base/message_loop/message_loop.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" @@ -220,8 +221,11 @@ int MPEGAudioStreamParserBase::ParseFrame(const uint8_t* data, timestamp_helper_.reset(new AudioTimestampHelper(sample_rate)); timestamp_helper_->SetBaseTimestamp(base_timestamp); - VideoDecoderConfig video_config; - if (!config_cb_.Run(config_, video_config, TextTrackConfigMap())) + scoped_ptr media_tracks(new MediaTracks()); + if (config_.IsValidConfig()) { + media_tracks->AddAudioTrack(config_, "audio", "", "", ""); + } + if (!config_cb_.Run(std::move(media_tracks), TextTrackConfigMap())) return -1; if (!init_cb_.is_null()) { diff --git a/media/formats/webm/webm_stream_parser.cc b/media/formats/webm/webm_stream_parser.cc index e36a972adec9a0..3090768a5229ff 100644 --- a/media/formats/webm/webm_stream_parser.cc +++ b/media/formats/webm/webm_stream_parser.cc @@ -9,6 +9,8 @@ #include "base/callback.h" #include "base/callback_helpers.h" #include "base/logging.h" +#include "media/base/media_track.h" +#include "media/base/media_tracks.h" #include "media/base/timestamp_constants.h" #include "media/formats/webm/webm_cluster_parser.h" #include "media/formats/webm/webm_constants.h" @@ -222,9 +224,16 @@ int WebMStreamParser::ParseInfoAndTracks(const uint8_t* data, int size) { if (video_config.is_encrypted()) OnEncryptedMediaInitData(tracks_parser.video_encryption_key_id()); - if (!config_cb_.Run(audio_config, - video_config, - tracks_parser.text_tracks())) { + scoped_ptr media_tracks(new MediaTracks()); + // TODO(servolk): Implement proper sourcing of media track info as described + // in crbug.com/590085 + if (audio_config.IsValidConfig()) { + media_tracks->AddAudioTrack(audio_config, "audio", "", "", ""); + } + if (video_config.IsValidConfig()) { + media_tracks->AddVideoTrack(video_config, "video", "", "", ""); + } + if (!config_cb_.Run(std::move(media_tracks), tracks_parser.text_tracks())) { DVLOG(1) << "New config data isn't allowed."; return -1; } diff --git a/media/media.gyp b/media/media.gyp index 825dc8576b727a..5fe1f159e1b3fe 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -363,6 +363,10 @@ 'base/media_resources.h', 'base/media_switches.cc', 'base/media_switches.h', + 'base/media_track.cc', + 'base/media_track.h', + 'base/media_tracks.cc', + 'base/media_tracks.h', 'base/media_util.cc', 'base/media_util.h', 'base/mime_util.cc', diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc index 80871f98c7b7ef..51a845bc5b12e6 100644 --- a/media/test/pipeline_integration_test.cc +++ b/media/test/pipeline_integration_test.cc @@ -21,6 +21,7 @@ #include "media/base/media.h" #include "media/base/media_keys.h" #include "media/base/media_switches.h" +#include "media/base/media_tracks.h" #include "media/base/test_data_util.h" #include "media/base/timestamp_constants.h" #include "media/cdm/aes_decryptor.h" @@ -636,7 +637,7 @@ class MockMediaSource { return last_timestamp_offset_; } - MOCK_METHOD0(InitSegmentReceived, void(void)); + MOCK_METHOD1(InitSegmentReceived, void(const MediaTracks&)); private: scoped_refptr file_data_; @@ -682,7 +683,7 @@ class PipelineIntegrationTestHost : public testing::Test, class PipelineIntegrationTest : public PipelineIntegrationTestHost { public: void StartPipelineWithMediaSource(MockMediaSource* source) { - EXPECT_CALL(*source, InitSegmentReceived()).Times(AtLeast(1)); + EXPECT_CALL(*source, InitSegmentReceived(_)).Times(AtLeast(1)); EXPECT_CALL(*this, OnMetadata(_)) .Times(AtMost(1)) .WillRepeatedly(SaveArg<0>(&metadata_)); @@ -726,7 +727,7 @@ class PipelineIntegrationTest : public PipelineIntegrationTestHost { void StartPipelineWithEncryptedMedia(MockMediaSource* source, FakeEncryptedMedia* encrypted_media) { - EXPECT_CALL(*source, InitSegmentReceived()).Times(AtLeast(1)); + EXPECT_CALL(*source, InitSegmentReceived(_)).Times(AtLeast(1)); EXPECT_CALL(*this, OnMetadata(_)) .Times(AtMost(1)) .WillRepeatedly(SaveArg<0>(&metadata_));