diff --git a/media/formats/mp2t/es_parser_h264.cc b/media/formats/mp2t/es_parser_h264.cc index 472b9fa197..0b17d76e6c 100644 --- a/media/formats/mp2t/es_parser_h264.cc +++ b/media/formats/mp2t/es_parser_h264.cc @@ -39,7 +39,8 @@ EsParserH264::EsParserH264( next_access_unit_pos_(0), stream_converter_(new H264ByteToUnitStreamConverter), decoder_config_check_pending_(false), - pending_sample_duration_(0) { + pending_sample_duration_(0), + waiting_for_key_frame_(true) { } EsParserH264::~EsParserH264() { @@ -102,6 +103,7 @@ void EsParserH264::Reset() { decoder_config_check_pending_ = false; pending_sample_ = scoped_refptr(); pending_sample_duration_ = 0; + waiting_for_key_frame_ = true; } bool EsParserH264::FindAUD(int64* stream_pos) { @@ -233,9 +235,14 @@ bool EsParserH264::ParseInternal() { } } - // Emit a frame and move the stream to the next AUD position. - RCHECK(EmitFrame(current_access_unit_pos_, access_unit_size, - is_key_frame, pps_id_for_access_unit)); + if (waiting_for_key_frame_) { + waiting_for_key_frame_ = !is_key_frame; + } + if (!waiting_for_key_frame_) { + // Emit a frame and move the stream to the next AUD position. + RCHECK(EmitFrame(current_access_unit_pos_, access_unit_size, + is_key_frame, pps_id_for_access_unit)); + } current_access_unit_pos_ = next_access_unit_pos_; es_queue_->Trim(current_access_unit_pos_); diff --git a/media/formats/mp2t/es_parser_h264.h b/media/formats/mp2t/es_parser_h264.h index 8f5ab7f85c..bcc00a79c1 100644 --- a/media/formats/mp2t/es_parser_h264.h +++ b/media/formats/mp2t/es_parser_h264.h @@ -94,6 +94,9 @@ class EsParserH264 : public EsParser { // Frame for which we do not yet have a duration. scoped_refptr pending_sample_; uint64 pending_sample_duration_; + + // Indicates whether waiting for first key frame. + bool waiting_for_key_frame_; }; } // namespace mp2t diff --git a/media/formats/mp2t/es_parser_h264_unittest.cc b/media/formats/mp2t/es_parser_h264_unittest.cc index ae06f89218..ced13709b4 100644 --- a/media/formats/mp2t/es_parser_h264_unittest.cc +++ b/media/formats/mp2t/es_parser_h264_unittest.cc @@ -117,20 +117,24 @@ void AppendAUD( class EsParserH264Test : public testing::Test { public: - EsParserH264Test() : sample_count_(0) { - } + EsParserH264Test() + : sample_count_(0), + first_frame_is_key_frame_(false) {} void LoadStream(const char* filename); void ProcessPesPackets(const std::vector& pes_packets); void EmitSample(uint32 pid, scoped_refptr& sample) { sample_count_++; + if (sample_count_ == 1) + first_frame_is_key_frame_ = sample->is_key_frame(); } void NewVideoConfig(scoped_refptr& config) { } size_t sample_count() const { return sample_count_; } + bool first_frame_is_key_frame() { return first_frame_is_key_frame_; } // Stream with AUD NALUs. std::vector stream_; @@ -140,6 +144,7 @@ class EsParserH264Test : public testing::Test { protected: size_t sample_count_; + bool first_frame_is_key_frame_; }; void EsParserH264Test::LoadStream(const char* filename) { @@ -204,7 +209,8 @@ TEST_F(EsParserH264Test, OneAccessUnitPerPes) { // Process each PES packet. ProcessPesPackets(pes_packets); - ASSERT_EQ(sample_count(), access_units_.size()); + EXPECT_EQ(sample_count(), access_units_.size()); + EXPECT_TRUE(first_frame_is_key_frame()); } TEST_F(EsParserH264Test, NonAlignedPesPacket) { @@ -228,7 +234,8 @@ TEST_F(EsParserH264Test, NonAlignedPesPacket) { // Process each PES packet. ProcessPesPackets(pes_packets); - ASSERT_EQ(sample_count(), access_units_.size()); + EXPECT_EQ(sample_count(), access_units_.size()); + EXPECT_TRUE(first_frame_is_key_frame()); } TEST_F(EsParserH264Test, SeveralPesPerAccessUnit) { @@ -258,7 +265,21 @@ TEST_F(EsParserH264Test, SeveralPesPerAccessUnit) { // Process each PES packet. ProcessPesPackets(pes_packets); - ASSERT_EQ(sample_count(), access_units_.size()); + EXPECT_EQ(sample_count(), access_units_.size()); + EXPECT_TRUE(first_frame_is_key_frame()); +} + +TEST_F(EsParserH264Test, NonIFrameStart) { + LoadStream("bear_no_iframe_start.h264"); + + // One to one equivalence between PES packets and access units. + std::vector pes_packets(access_units_); + + // Process each PES packet. + ProcessPesPackets(pes_packets); + // Ensure samples were emitted, but fewer than number of AUDs. + EXPECT_LT(sample_count(), access_units_.size()); + EXPECT_TRUE(first_frame_is_key_frame()); } } // namespace mp2t diff --git a/media/test/data/README b/media/test/data/README index e3e8699710..ee0d0ab0f9 100644 --- a/media/test/data/README +++ b/media/test/data/README @@ -75,5 +75,8 @@ bear.h264: ffmpeg -i bear.mp4 -vcodec copy -vbsf h264_mp4toannexb \ -an bear.h264 +bear_no_i_frame_start.h264 + Derived from bear.h264. Consists of 29-non-I-frames, followed by a single I-frame, and 29 non-I-frames. + avc-byte-stream-frame.h264 - Single IDR frame extracted from test-25fps.h264 in Annex B byte stream format. avc-unit-stream-frame.h264 - Single IDR frame from avc-byte-stream-frame.h264 converted to unit stream format. diff --git a/media/test/data/bear_no_iframe_start.h264 b/media/test/data/bear_no_iframe_start.h264 new file mode 100644 index 0000000000..8bb175d703 Binary files /dev/null and b/media/test/data/bear_no_iframe_start.h264 differ