diff --git a/packager/media/base/media_parser.h b/packager/media/base/media_parser.h index 6339e3c06f..c10e36b094 100644 --- a/packager/media/base/media_parser.h +++ b/packager/media/base/media_parser.h @@ -20,6 +20,7 @@ namespace media { class KeySource; class MediaSample; class StreamInfo; +class TextSample; class MediaParser { public: @@ -39,18 +40,31 @@ class MediaParser { /// @return true if the sample is accepted, false if something was wrong /// with the sample and a parsing error should be signaled. typedef base::Callback& media_sample)> - NewSampleCB; + std::shared_ptr media_sample)> + NewMediaSampleCB; + + /// Called when a new text sample has been parsed. + /// @param track_id is the track id of the new sample. + /// @param text_sample is the new text sample. + /// @return true if the sample is accepted, false if something was wrong + /// with the sample and a parsing error should be signaled. + typedef base::Callback text_sample)> + NewTextSampleCB; /// Initialize the parser with necessary callbacks. Must be called before any /// data is passed to Parse(). /// @param init_cb will be called once enough data has been parsed to /// determine the initial stream configurations. - /// @param new_sample_cb will be called each time a new media sample is - /// available from the parser. May be NULL, and caller retains - /// ownership. + /// @param new_media_sample_cb will be called each time a new media sample is + /// available from the parser. + /// @param new_text_sample_cb will be called each time a new text sample is + /// available from the parser. + /// @param decryption_key_source the key source to decrypt the frames. May be + /// NULL, and caller retains ownership. virtual void Init(const InitCB& init_cb, - const NewSampleCB& new_sample_cb, + const NewMediaSampleCB& new_media_sample_cb, + const NewTextSampleCB& new_text_sample_cb, KeySource* decryption_key_source) = 0; /// Flush data currently in the parser and put the parser in a state where it diff --git a/packager/media/demuxer/demuxer.cc b/packager/media/demuxer/demuxer.cc index e089595cee..c902a76e98 100644 --- a/packager/media/demuxer/demuxer.cc +++ b/packager/media/demuxer/demuxer.cc @@ -147,12 +147,6 @@ void Demuxer::SetLanguageOverride(const std::string& stream_label, language_overrides_[stream_index] = language_override; } -Demuxer::QueuedSample::QueuedSample(uint32_t local_track_id, - std::shared_ptr local_sample) - : track_id(local_track_id), sample(local_sample) {} - -Demuxer::QueuedSample::~QueuedSample() {} - Status Demuxer::InitializeParser() { DCHECK(!media_file_); DCHECK(!all_streams_ready_); @@ -213,9 +207,11 @@ Status Demuxer::InitializeParser() { return Status(error::UNIMPLEMENTED, "Container not supported."); } - parser_->Init(base::Bind(&Demuxer::ParserInitEvent, base::Unretained(this)), - base::Bind(&Demuxer::NewSampleEvent, base::Unretained(this)), - key_source_.get()); + parser_->Init( + base::Bind(&Demuxer::ParserInitEvent, base::Unretained(this)), + base::Bind(&Demuxer::NewMediaSampleEvent, base::Unretained(this)), + base::Bind(&Demuxer::NewTextSampleEvent, base::Unretained(this)), + key_source_.get()); // Handle trailing 'moov'. if (container_name_ == CONTAINER_MOV && @@ -294,31 +290,56 @@ void Demuxer::ParserInitEvent( all_streams_ready_ = true; } -bool Demuxer::NewSampleEvent(uint32_t track_id, - const std::shared_ptr& sample) { +bool Demuxer::NewMediaSampleEvent(uint32_t track_id, + std::shared_ptr sample) { if (!all_streams_ready_) { - if (queued_samples_.size() >= kQueuedSamplesLimit) { + if (queued_media_samples_.size() >= kQueuedSamplesLimit) { LOG(ERROR) << "Queued samples limit reached: " << kQueuedSamplesLimit; return false; } - queued_samples_.push_back(QueuedSample(track_id, sample)); + queued_media_samples_.emplace_back(track_id, sample); return true; } if (!init_event_status_.ok()) { return false; } - while (!queued_samples_.empty()) { - if (!PushSample(queued_samples_.front().track_id, - queued_samples_.front().sample)) { + + while (!queued_media_samples_.empty()) { + if (!PushMediaSample(queued_media_samples_.front().track_id, + queued_media_samples_.front().sample)) { return false; } - queued_samples_.pop_front(); + queued_media_samples_.pop_front(); } - return PushSample(track_id, sample); + return PushMediaSample(track_id, sample); } -bool Demuxer::PushSample(uint32_t track_id, - const std::shared_ptr& sample) { +bool Demuxer::NewTextSampleEvent(uint32_t track_id, + std::shared_ptr sample) { + if (!all_streams_ready_) { + if (queued_text_samples_.size() >= kQueuedSamplesLimit) { + LOG(ERROR) << "Queued samples limit reached: " << kQueuedSamplesLimit; + return false; + } + queued_text_samples_.emplace_back(track_id, sample); + return true; + } + if (!init_event_status_.ok()) { + return false; + } + + while (!queued_text_samples_.empty()) { + if (!PushTextSample(queued_text_samples_.front().track_id, + queued_text_samples_.front().sample)) { + return false; + } + queued_text_samples_.pop_front(); + } + return PushTextSample(track_id, sample); +} + +bool Demuxer::PushMediaSample(uint32_t track_id, + std::shared_ptr sample) { auto stream_index_iter = track_id_to_stream_index_map_.find(track_id); if (stream_index_iter == track_id_to_stream_index_map_.end()) { LOG(ERROR) << "Track " << track_id << " not found."; @@ -330,8 +351,27 @@ bool Demuxer::PushSample(uint32_t track_id, if (!status.ok()) { LOG(ERROR) << "Failed to process sample " << stream_index_iter->second << " " << status; + return false; } - return status.ok(); + return true; +} + +bool Demuxer::PushTextSample(uint32_t track_id, + std::shared_ptr sample) { + auto stream_index_iter = track_id_to_stream_index_map_.find(track_id); + if (stream_index_iter == track_id_to_stream_index_map_.end()) { + LOG(ERROR) << "Track " << track_id << " not found."; + return false; + } + if (stream_index_iter->second == kInvalidStreamIndex) + return true; + Status status = DispatchTextSample(stream_index_iter->second, sample); + if (!status.ok()) { + LOG(ERROR) << "Failed to process sample " << stream_index_iter->second + << " " << status; + return false; + } + return true; } Status Demuxer::Parse() { diff --git a/packager/media/demuxer/demuxer.h b/packager/media/demuxer/demuxer.h index 631208dde1..5a5aaa4c89 100644 --- a/packager/media/demuxer/demuxer.h +++ b/packager/media/demuxer/demuxer.h @@ -94,12 +94,15 @@ class Demuxer : public OriginHandler { Demuxer(const Demuxer&) = delete; Demuxer& operator=(const Demuxer&) = delete; + template struct QueuedSample { - QueuedSample(uint32_t track_id, std::shared_ptr sample); - ~QueuedSample(); + QueuedSample(uint32_t track_id, std::shared_ptr sample) + : track_id(track_id), sample(sample) {} + + ~QueuedSample() {} uint32_t track_id; - std::shared_ptr sample; + std::shared_ptr sample; }; // Initialize the parser. This method primes the demuxer by parsing portions @@ -112,11 +115,13 @@ class Demuxer : public OriginHandler { // Parser new sample event handler. Queues the samples if init event has not // been received, otherwise calls PushSample() to push the sample to // corresponding stream. - bool NewSampleEvent(uint32_t track_id, - const std::shared_ptr& sample); + bool NewMediaSampleEvent(uint32_t track_id, + std::shared_ptr sample); + bool NewTextSampleEvent(uint32_t track_id, + std::shared_ptr sample); // Helper function to push the sample to corresponding stream. - bool PushSample(uint32_t track_id, - const std::shared_ptr& sample); + bool PushMediaSample(uint32_t track_id, std::shared_ptr sample); + bool PushTextSample(uint32_t track_id, std::shared_ptr sample); // Read from the source and send it to the parser. Status Parse(); @@ -126,7 +131,8 @@ class Demuxer : public OriginHandler { // A stream is considered ready after receiving the stream info. bool all_streams_ready_ = false; // Queued samples received in NewSampleEvent() before ParserInitEvent(). - std::deque queued_samples_; + std::deque> queued_media_samples_; + std::deque> queued_text_samples_; std::unique_ptr parser_; // TrackId -> StreamIndex map. std::map track_id_to_stream_index_map_; diff --git a/packager/media/formats/mp2t/mp2t_media_parser.cc b/packager/media/formats/mp2t/mp2t_media_parser.cc index 0e003defa7..d77622de41 100644 --- a/packager/media/formats/mp2t/mp2t_media_parser.cc +++ b/packager/media/formats/mp2t/mp2t_media_parser.cc @@ -149,17 +149,17 @@ Mp2tMediaParser::Mp2tMediaParser() Mp2tMediaParser::~Mp2tMediaParser() {} -void Mp2tMediaParser::Init( - const InitCB& init_cb, - const NewSampleCB& new_sample_cb, - KeySource* decryption_key_source) { +void Mp2tMediaParser::Init(const InitCB& init_cb, + const NewMediaSampleCB& new_media_sample_cb, + const NewTextSampleCB& new_text_sample_cb, + KeySource* decryption_key_source) { DCHECK(!is_initialized_); DCHECK(init_cb_.is_null()); DCHECK(!init_cb.is_null()); - DCHECK(!new_sample_cb.is_null()); + DCHECK(!new_media_sample_cb.is_null()); init_cb_ = init_cb; - new_sample_cb_ = new_sample_cb; + new_sample_cb_ = new_media_sample_cb; } bool Mp2tMediaParser::Flush() { diff --git a/packager/media/formats/mp2t/mp2t_media_parser.h b/packager/media/formats/mp2t/mp2t_media_parser.h index 2ad7fbd733..06cfec1dc1 100644 --- a/packager/media/formats/mp2t/mp2t_media_parser.h +++ b/packager/media/formats/mp2t/mp2t_media_parser.h @@ -34,7 +34,8 @@ class Mp2tMediaParser : public MediaParser { /// @name MediaParser implementation overrides. /// @{ void Init(const InitCB& init_cb, - const NewSampleCB& new_sample_cb, + const NewMediaSampleCB& new_media_sample_cb, + const NewTextSampleCB& new_text_sample_cb, KeySource* decryption_key_source) override; bool Flush() override WARN_UNUSED_RESULT; bool Parse(const uint8_t* buf, int size) override WARN_UNUSED_RESULT; @@ -74,7 +75,7 @@ class Mp2tMediaParser : public MediaParser { // List of callbacks. InitCB init_cb_; - NewSampleCB new_sample_cb_; + NewMediaSampleCB new_sample_cb_; bool sbr_in_mimetype_; diff --git a/packager/media/formats/mp2t/mp2t_media_parser_unittest.cc b/packager/media/formats/mp2t/mp2t_media_parser_unittest.cc index 15959bf200..639039d5c8 100644 --- a/packager/media/formats/mp2t/mp2t_media_parser_unittest.cc +++ b/packager/media/formats/mp2t/mp2t_media_parser_unittest.cc @@ -69,8 +69,7 @@ class Mp2tMediaParserTest : public testing::Test { } } - bool OnNewSample(uint32_t track_id, - const std::shared_ptr& sample) { + bool OnNewSample(uint32_t track_id, std::shared_ptr sample) { StreamMap::const_iterator stream = stream_map_.find(track_id); EXPECT_NE(stream_map_.end(), stream); if (stream != stream_map_.end()) { @@ -97,11 +96,15 @@ class Mp2tMediaParserTest : public testing::Test { return true; } + bool OnNewTextSample(uint32_t track_id, std::shared_ptr sample) { + return false; + } + void InitializeParser() { parser_->Init( - base::Bind(&Mp2tMediaParserTest::OnInit, - base::Unretained(this)), - base::Bind(&Mp2tMediaParserTest::OnNewSample, + base::Bind(&Mp2tMediaParserTest::OnInit, base::Unretained(this)), + base::Bind(&Mp2tMediaParserTest::OnNewSample, base::Unretained(this)), + base::Bind(&Mp2tMediaParserTest::OnNewTextSample, base::Unretained(this)), NULL); } diff --git a/packager/media/formats/mp4/mp4_media_parser.cc b/packager/media/formats/mp4/mp4_media_parser.cc index 7cbb445b1b..45bd369b30 100644 --- a/packager/media/formats/mp4/mp4_media_parser.cc +++ b/packager/media/formats/mp4/mp4_media_parser.cc @@ -179,16 +179,17 @@ MP4MediaParser::MP4MediaParser() MP4MediaParser::~MP4MediaParser() {} void MP4MediaParser::Init(const InitCB& init_cb, - const NewSampleCB& new_sample_cb, + const NewMediaSampleCB& new_media_sample_cb, + const NewTextSampleCB& new_text_sample_cb, KeySource* decryption_key_source) { DCHECK_EQ(state_, kWaitingForInit); DCHECK(init_cb_.is_null()); DCHECK(!init_cb.is_null()); - DCHECK(!new_sample_cb.is_null()); + DCHECK(!new_media_sample_cb.is_null()); ChangeState(kParsingBoxes); init_cb_ = init_cb; - new_sample_cb_ = new_sample_cb; + new_sample_cb_ = new_media_sample_cb; decryption_key_source_ = decryption_key_source; if (decryption_key_source) decryptor_source_.reset(new DecryptorSource(decryption_key_source)); diff --git a/packager/media/formats/mp4/mp4_media_parser.h b/packager/media/formats/mp4/mp4_media_parser.h index 4b51b9e4a0..b474729a81 100644 --- a/packager/media/formats/mp4/mp4_media_parser.h +++ b/packager/media/formats/mp4/mp4_media_parser.h @@ -35,7 +35,8 @@ class MP4MediaParser : public MediaParser { /// @name MediaParser implementation overrides. /// @{ void Init(const InitCB& init_cb, - const NewSampleCB& new_sample_cb, + const NewMediaSampleCB& new_media_sample_cb, + const NewTextSampleCB& new_text_sample_cb, KeySource* decryption_key_source) override; bool Flush() override WARN_UNUSED_RESULT; bool Parse(const uint8_t* buf, int size) override WARN_UNUSED_RESULT; @@ -82,7 +83,7 @@ class MP4MediaParser : public MediaParser { State state_; InitCB init_cb_; - NewSampleCB new_sample_cb_; + NewMediaSampleCB new_sample_cb_; KeySource* decryption_key_source_; std::unique_ptr decryptor_source_; diff --git a/packager/media/formats/mp4/mp4_media_parser_unittest.cc b/packager/media/formats/mp4/mp4_media_parser_unittest.cc index ba62152a4e..953b6c3c7a 100644 --- a/packager/media/formats/mp4/mp4_media_parser_unittest.cc +++ b/packager/media/formats/mp4/mp4_media_parser_unittest.cc @@ -82,18 +82,22 @@ class MP4MediaParserTest : public testing::Test { num_samples_ = 0; } - bool NewSampleF(uint32_t track_id, - const std::shared_ptr& sample) { + bool NewSampleF(uint32_t track_id, std::shared_ptr sample) { DVLOG(2) << "Track Id: " << track_id << " " << sample->ToString(); ++num_samples_; return true; } + bool NewTextSampleF(uint32_t track_id, std::shared_ptr sample) { + return false; + } + void InitializeParser(KeySource* decryption_key_source) { parser_->Init( base::Bind(&MP4MediaParserTest::InitF, base::Unretained(this)), base::Bind(&MP4MediaParserTest::NewSampleF, base::Unretained(this)), + base::Bind(&MP4MediaParserTest::NewTextSampleF, base::Unretained(this)), decryption_key_source); } diff --git a/packager/media/formats/webm/webm_cluster_parser.cc b/packager/media/formats/webm/webm_cluster_parser.cc index b3dca771b6..0afffa0e8c 100644 --- a/packager/media/formats/webm/webm_cluster_parser.cc +++ b/packager/media/formats/webm/webm_cluster_parser.cc @@ -37,7 +37,7 @@ WebMClusterParser::WebMClusterParser( const std::set& ignored_tracks, const std::string& audio_encryption_key_id, const std::string& video_encryption_key_id, - const MediaParser::NewSampleCB& new_sample_cb, + const MediaParser::NewMediaSampleCB& new_sample_cb, const MediaParser::InitCB& init_cb, KeySource* decryption_key_source) : timecode_multiplier_(timecode_scale / @@ -482,10 +482,11 @@ bool WebMClusterParser::OnBlock(bool is_simple_block, return track->EmitBuffer(buffer); } -WebMClusterParser::Track::Track(int track_num, - bool is_video, - int64_t default_duration, - const MediaParser::NewSampleCB& new_sample_cb) +WebMClusterParser::Track::Track( + int track_num, + bool is_video, + int64_t default_duration, + const MediaParser::NewMediaSampleCB& new_sample_cb) : track_num_(track_num), is_video_(is_video), default_duration_(default_duration), diff --git a/packager/media/formats/webm/webm_cluster_parser.h b/packager/media/formats/webm/webm_cluster_parser.h index e4e7a7a8b7..5f6f431632 100644 --- a/packager/media/formats/webm/webm_cluster_parser.h +++ b/packager/media/formats/webm/webm_cluster_parser.h @@ -41,7 +41,7 @@ class WebMClusterParser : public WebMParserClient { Track(int track_num, bool is_video, int64_t default_duration, - const MediaParser::NewSampleCB& new_sample_cb); + const MediaParser::NewMediaSampleCB& new_sample_cb); ~Track(); int track_num() const { return track_num_; } @@ -89,7 +89,7 @@ class WebMClusterParser : public WebMParserClient { // only if |default_duration_| is kNoTimestamp. int64_t estimated_next_frame_duration_; - MediaParser::NewSampleCB new_sample_cb_; + MediaParser::NewMediaSampleCB new_sample_cb_; }; typedef std::map TextTrackMap; @@ -129,7 +129,7 @@ class WebMClusterParser : public WebMParserClient { const std::set& ignored_tracks, const std::string& audio_encryption_key_id, const std::string& video_encryption_key_id, - const MediaParser::NewSampleCB& new_sample_cb, + const MediaParser::NewMediaSampleCB& new_sample_cb, const MediaParser::InitCB& init_cb, KeySource* decryption_key_source); ~WebMClusterParser() override; diff --git a/packager/media/formats/webm/webm_cluster_parser_unittest.cc b/packager/media/formats/webm/webm_cluster_parser_unittest.cc index 76d3dc94e2..8f883c00c4 100644 --- a/packager/media/formats/webm/webm_cluster_parser_unittest.cc +++ b/packager/media/formats/webm/webm_cluster_parser_unittest.cc @@ -377,8 +377,7 @@ class WebMClusterParserTest : public testing::Test { streams_from_init_event_ = stream_info; } - bool NewSampleEvent(uint32_t track_id, - const std::shared_ptr& sample) { + bool NewSampleEvent(uint32_t track_id, std::shared_ptr sample) { switch (track_id) { case kAudioTrackNum: audio_buffers_.push_back(sample); diff --git a/packager/media/formats/webm/webm_media_parser.cc b/packager/media/formats/webm/webm_media_parser.cc index fc13148a61..fa43542563 100644 --- a/packager/media/formats/webm/webm_media_parser.cc +++ b/packager/media/formats/webm/webm_media_parser.cc @@ -26,16 +26,17 @@ WebMMediaParser::WebMMediaParser() WebMMediaParser::~WebMMediaParser() {} void WebMMediaParser::Init(const InitCB& init_cb, - const NewSampleCB& new_sample_cb, + const NewMediaSampleCB& new_media_sample_cb, + const NewTextSampleCB& new_text_sample_cb, KeySource* decryption_key_source) { DCHECK_EQ(state_, kWaitingForInit); DCHECK(init_cb_.is_null()); DCHECK(!init_cb.is_null()); - DCHECK(!new_sample_cb.is_null()); + DCHECK(!new_media_sample_cb.is_null()); ChangeState(kParsingHeaders); init_cb_ = init_cb; - new_sample_cb_ = new_sample_cb; + new_sample_cb_ = new_media_sample_cb; decryption_key_source_ = decryption_key_source; ignore_text_tracks_ = true; } diff --git a/packager/media/formats/webm/webm_media_parser.h b/packager/media/formats/webm/webm_media_parser.h index b0ba0c7492..aeca4f3258 100644 --- a/packager/media/formats/webm/webm_media_parser.h +++ b/packager/media/formats/webm/webm_media_parser.h @@ -23,7 +23,8 @@ class WebMMediaParser : public MediaParser { /// @name MediaParser implementation overrides. /// @{ void Init(const InitCB& init_cb, - const NewSampleCB& new_sample_cb, + const NewMediaSampleCB& new_media_sample_cb, + const NewTextSampleCB& new_text_sample_cb, KeySource* decryption_key_source) override; bool Flush() override WARN_UNUSED_RESULT; bool Parse(const uint8_t* buf, int size) override WARN_UNUSED_RESULT; @@ -64,7 +65,7 @@ class WebMMediaParser : public MediaParser { State state_; InitCB init_cb_; - NewSampleCB new_sample_cb_; + NewMediaSampleCB new_sample_cb_; KeySource* decryption_key_source_; bool ignore_text_tracks_; diff --git a/packager/media/formats/wvm/wvm_media_parser.cc b/packager/media/formats/wvm/wvm_media_parser.cc index 85d353a920..f027278440 100644 --- a/packager/media/formats/wvm/wvm_media_parser.cc +++ b/packager/media/formats/wvm/wvm_media_parser.cc @@ -112,14 +112,15 @@ WvmMediaParser::WvmMediaParser() WvmMediaParser::~WvmMediaParser() {} void WvmMediaParser::Init(const InitCB& init_cb, - const NewSampleCB& new_sample_cb, + const NewMediaSampleCB& new_media_sample_cb, + const NewTextSampleCB& new_text_sample_cb, KeySource* decryption_key_source) { DCHECK(!is_initialized_); DCHECK(!init_cb.is_null()); - DCHECK(!new_sample_cb.is_null()); + DCHECK(!new_media_sample_cb.is_null()); decryption_key_source_ = decryption_key_source; init_cb_ = init_cb; - new_sample_cb_ = new_sample_cb; + new_sample_cb_ = new_media_sample_cb; } bool WvmMediaParser::Parse(const uint8_t* buf, int size) { diff --git a/packager/media/formats/wvm/wvm_media_parser.h b/packager/media/formats/wvm/wvm_media_parser.h index e1f79cfe1c..74aa639128 100644 --- a/packager/media/formats/wvm/wvm_media_parser.h +++ b/packager/media/formats/wvm/wvm_media_parser.h @@ -56,7 +56,8 @@ class WvmMediaParser : public MediaParser { /// @name MediaParser implementation overrides. /// @{ void Init(const InitCB& init_cb, - const NewSampleCB& new_sample_cb, + const NewMediaSampleCB& new_media_sample_cb, + const NewTextSampleCB& new_text_sample_cb, KeySource* decryption_key_source) override; bool Flush() override WARN_UNUSED_RESULT; bool Parse(const uint8_t* buf, int size) override WARN_UNUSED_RESULT; @@ -216,7 +217,7 @@ class WvmMediaParser : public MediaParser { // List of callbacks.t InitCB init_cb_; - NewSampleCB new_sample_cb_; + NewMediaSampleCB new_sample_cb_; // Whether |init_cb_| has been invoked. bool is_initialized_; diff --git a/packager/media/formats/wvm/wvm_media_parser_unittest.cc b/packager/media/formats/wvm/wvm_media_parser_unittest.cc index 16499a247e..4984bda34f 100644 --- a/packager/media/formats/wvm/wvm_media_parser_unittest.cc +++ b/packager/media/formats/wvm/wvm_media_parser_unittest.cc @@ -99,8 +99,7 @@ class WvmMediaParserTest : public testing::Test { } } - bool OnNewSample(uint32_t track_id, - const std::shared_ptr& sample) { + bool OnNewSample(uint32_t track_id, std::shared_ptr sample) { std::string stream_type; if (static_cast(track_id) != current_track_id_) { // onto next track. @@ -138,11 +137,15 @@ class WvmMediaParserTest : public testing::Test { return true; } + bool OnNewTextSample(uint32_t track_id, std::shared_ptr sample) { + return false; + } + void InitializeParser() { parser_->Init( - base::Bind(&WvmMediaParserTest::OnInit, - base::Unretained(this)), - base::Bind(&WvmMediaParserTest::OnNewSample, + base::Bind(&WvmMediaParserTest::OnInit, base::Unretained(this)), + base::Bind(&WvmMediaParserTest::OnNewSample, base::Unretained(this)), + base::Bind(&WvmMediaParserTest::OnNewTextSample, base::Unretained(this)), key_source_.get()); }