From 30cb6948e52244ca5f2e6c2742898473fb0b04f3 Mon Sep 17 00:00:00 2001 From: Kongqun Yang Date: Thu, 24 Apr 2014 11:37:33 -0700 Subject: [PATCH] Add MediaParser::Flush to flush the parser Change-Id: Ic12a045dda47ccd270c8c3e9e83768e04a53ad58 --- media/base/demuxer.cc | 8 +++-- media/base/media_parser.h | 4 +++ media/base/media_sample.h | 9 +++-- media/formats/mp2t/es_parser_h264.cc | 3 -- media/formats/mp4/mp4_media_parser.cc | 10 +++++- media/formats/mp4/mp4_media_parser.h | 1 + .../formats/mp4/mp4_media_parser_unittest.cc | 34 ++++++++++++++----- 7 files changed, 49 insertions(+), 20 deletions(-) diff --git a/media/base/demuxer.cc b/media/base/demuxer.cc index 9a8ba92771..9abfee5031 100644 --- a/media/base/demuxer.cc +++ b/media/base/demuxer.cc @@ -146,9 +146,11 @@ Status Demuxer::Parse() { int64 bytes_read = media_file_->Read(buffer_.get(), kBufSize); if (bytes_read <= 0) { - return media_file_->Eof() - ? Status(error::END_OF_STREAM, "End of stream.") - : Status(error::FILE_FAILURE, "Cannot read file " + file_name_); + if (media_file_->Eof()) { + parser_->Flush(); + return Status(error::END_OF_STREAM, ""); + } + return Status(error::FILE_FAILURE, "Cannot read file " + file_name_); } return parser_->Parse(buffer_.get(), bytes_read) diff --git a/media/base/media_parser.h b/media/base/media_parser.h index 9aab158f99..399134b465 100644 --- a/media/base/media_parser.h +++ b/media/base/media_parser.h @@ -55,6 +55,10 @@ class MediaParser { const NewSampleCB& new_sample_cb, const NeedKeyCB& need_key_cb) = 0; + /// Flush data currently in the parser and put the parser in a state where it + /// can receive data for a new seek point. + virtual void Flush() = 0; + /// Should be called when there is new data to parse. /// @return true if successful. virtual bool Parse(const uint8* buf, int size) = 0; diff --git a/media/base/media_sample.h b/media/base/media_sample.h index 4047f2702d..99c23eda98 100644 --- a/media/base/media_sample.h +++ b/media/base/media_sample.h @@ -129,12 +129,12 @@ class MediaSample : public base::RefCountedThreadSafe { /// @return a human-readable string describing |*this|. std::string ToString() const; - protected: + private: friend class base::RefCountedThreadSafe; - /// Create a MediaSample. Buffer will be padded and aligned as necessary. - /// @param data,side_data can be NULL, which indicates an empty sample. - /// @param size,side_data_size should not be negative. + // Create a MediaSample. Buffer will be padded and aligned as necessary. + // |data|,|side_data| can be NULL, which indicates an empty sample. + // |size|,|side_data_size| should not be negative. MediaSample(const uint8* data, size_t size, const uint8* side_data, @@ -142,7 +142,6 @@ class MediaSample : public base::RefCountedThreadSafe { bool is_key_frame); virtual ~MediaSample(); - private: // Decoding time stamp. int64 dts_; // Presentation time stamp. diff --git a/media/formats/mp2t/es_parser_h264.cc b/media/formats/mp2t/es_parser_h264.cc index c3482fb32a..986e7ac00a 100644 --- a/media/formats/mp2t/es_parser_h264.cc +++ b/media/formats/mp2t/es_parser_h264.cc @@ -24,9 +24,6 @@ namespace { // 3 bytes for the start code + 1 byte for the NALU type. const int kMinAUDSize = 4; -// Size of H.264 NALU length output by this SDK. -const uint8 kCommonNaluLengthSize = 4; - } // anonymous namespace EsParserH264::EsParserH264( diff --git a/media/formats/mp4/mp4_media_parser.cc b/media/formats/mp4/mp4_media_parser.cc index 5c1c277b33..59f4efc8ae 100644 --- a/media/formats/mp4/mp4_media_parser.cc +++ b/media/formats/mp4/mp4_media_parser.cc @@ -55,6 +55,12 @@ void MP4MediaParser::Reset() { mdat_tail_ = 0; } +void MP4MediaParser::Flush() { + DCHECK_NE(state_, kWaitingForInit); + Reset(); + ChangeState(kParsingBoxes); +} + bool MP4MediaParser::Parse(const uint8* buf, int size) { DCHECK_NE(state_, kWaitingForInit); @@ -295,9 +301,11 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) { bool MP4MediaParser::ParseMoof(BoxReader* reader) { // Must already have initialization segment. - RCHECK(moov_.get() && runs_.get()); + RCHECK(moov_.get()); MovieFragment moof; RCHECK(moof.Parse(reader)); + if (!runs_) + runs_.reset(new TrackRunIterator(moov_.get())); RCHECK(runs_->Init(moof)); EmitNeedKeyIfNecessary(moof.pssh); ChangeState(kEmittingSamples); diff --git a/media/formats/mp4/mp4_media_parser.h b/media/formats/mp4/mp4_media_parser.h index ea0f37dde9..cebae6c99e 100644 --- a/media/formats/mp4/mp4_media_parser.h +++ b/media/formats/mp4/mp4_media_parser.h @@ -35,6 +35,7 @@ class MP4MediaParser : public MediaParser { virtual void Init(const InitCB& init_cb, const NewSampleCB& new_sample_cb, const NeedKeyCB& need_key_cb) OVERRIDE; + virtual void Flush() OVERRIDE; virtual bool Parse(const uint8* buf, int size) OVERRIDE; /// @} diff --git a/media/formats/mp4/mp4_media_parser_unittest.cc b/media/formats/mp4/mp4_media_parser_unittest.cc index 43bff9e4b7..b8b42aa5c7 100644 --- a/media/formats/mp4/mp4_media_parser_unittest.cc +++ b/media/formats/mp4/mp4_media_parser_unittest.cc @@ -96,23 +96,41 @@ TEST_F(MP4MediaParserTest, MultiFragmentAppend) { ParseMP4File("bear-1280x720-av_frag.mp4", 768432); } +TEST_F(MP4MediaParserTest, Flush) { + // Flush while reading sample data, then start a new stream. + InitializeParser(); + + std::vector buffer = ReadTestDataFile("bear-1280x720-av_frag.mp4"); + EXPECT_TRUE(AppendDataInPieces(buffer.data(), 65536, 512)); + parser_->Flush(); + EXPECT_TRUE(AppendDataInPieces(buffer.data(), buffer.size(), 512)); +} + TEST_F(MP4MediaParserTest, Reinitialization) { InitializeParser(); - std::vector buffer = - ReadTestDataFile("bear-1280x720-av_frag.mp4"); - EXPECT_TRUE(AppendDataInPieces(buffer.data(), - buffer.size(), - 512)); - EXPECT_TRUE(AppendDataInPieces(buffer.data(), - buffer.size(), - 512)); + std::vector buffer = ReadTestDataFile("bear-1280x720-av_frag.mp4"); + EXPECT_TRUE(AppendDataInPieces(buffer.data(), buffer.size(), 512)); + EXPECT_TRUE(AppendDataInPieces(buffer.data(), buffer.size(), 512)); } TEST_F(MP4MediaParserTest, MPEG2_AAC_LC) { ParseMP4File("bear-mpeg2-aac-only_frag.mp4", 512); } +// Test that a moov box is not always required after Flush() is called. +TEST_F(MP4MediaParserTest, NoMoovAfterFlush) { + InitializeParser(); + + std::vector buffer = ReadTestDataFile("bear-1280x720-av_frag.mp4"); + EXPECT_TRUE(AppendDataInPieces(buffer.data(), buffer.size(), 512)); + parser_->Flush(); + + const int kFirstMoofOffset = 1307; + EXPECT_TRUE(AppendDataInPieces( + buffer.data() + kFirstMoofOffset, buffer.size() - kFirstMoofOffset, 512)); +} + TEST_F(MP4MediaParserTest, NON_FRAGMENTED_MP4) { ParseMP4File("bear-1280x720.mp4", 512); }