Changed es_parser_h264 to wait for initial I-frame to start emitting samples.

Change-Id: I7b9ca4a73a8765501a1c29e467e877e1eee5f9d9
This commit is contained in:
Thomas Inskip 2014-06-30 12:53:56 -07:00 committed by Gerrit Code Review
parent f609b2947c
commit fc85154bca
5 changed files with 43 additions and 9 deletions

View File

@ -39,7 +39,8 @@ EsParserH264::EsParserH264(
next_access_unit_pos_(0), next_access_unit_pos_(0),
stream_converter_(new H264ByteToUnitStreamConverter), stream_converter_(new H264ByteToUnitStreamConverter),
decoder_config_check_pending_(false), decoder_config_check_pending_(false),
pending_sample_duration_(0) { pending_sample_duration_(0),
waiting_for_key_frame_(true) {
} }
EsParserH264::~EsParserH264() { EsParserH264::~EsParserH264() {
@ -102,6 +103,7 @@ void EsParserH264::Reset() {
decoder_config_check_pending_ = false; decoder_config_check_pending_ = false;
pending_sample_ = scoped_refptr<MediaSample>(); pending_sample_ = scoped_refptr<MediaSample>();
pending_sample_duration_ = 0; pending_sample_duration_ = 0;
waiting_for_key_frame_ = true;
} }
bool EsParserH264::FindAUD(int64* stream_pos) { 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. if (waiting_for_key_frame_) {
RCHECK(EmitFrame(current_access_unit_pos_, access_unit_size, waiting_for_key_frame_ = !is_key_frame;
is_key_frame, pps_id_for_access_unit)); }
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_; current_access_unit_pos_ = next_access_unit_pos_;
es_queue_->Trim(current_access_unit_pos_); es_queue_->Trim(current_access_unit_pos_);

View File

@ -94,6 +94,9 @@ class EsParserH264 : public EsParser {
// Frame for which we do not yet have a duration. // Frame for which we do not yet have a duration.
scoped_refptr<MediaSample> pending_sample_; scoped_refptr<MediaSample> pending_sample_;
uint64 pending_sample_duration_; uint64 pending_sample_duration_;
// Indicates whether waiting for first key frame.
bool waiting_for_key_frame_;
}; };
} // namespace mp2t } // namespace mp2t

View File

@ -117,20 +117,24 @@ void AppendAUD(
class EsParserH264Test : public testing::Test { class EsParserH264Test : public testing::Test {
public: public:
EsParserH264Test() : sample_count_(0) { EsParserH264Test()
} : sample_count_(0),
first_frame_is_key_frame_(false) {}
void LoadStream(const char* filename); void LoadStream(const char* filename);
void ProcessPesPackets(const std::vector<Packet>& pes_packets); void ProcessPesPackets(const std::vector<Packet>& pes_packets);
void EmitSample(uint32 pid, scoped_refptr<MediaSample>& sample) { void EmitSample(uint32 pid, scoped_refptr<MediaSample>& sample) {
sample_count_++; sample_count_++;
if (sample_count_ == 1)
first_frame_is_key_frame_ = sample->is_key_frame();
} }
void NewVideoConfig(scoped_refptr<StreamInfo>& config) { void NewVideoConfig(scoped_refptr<StreamInfo>& config) {
} }
size_t sample_count() const { return sample_count_; } size_t sample_count() const { return sample_count_; }
bool first_frame_is_key_frame() { return first_frame_is_key_frame_; }
// Stream with AUD NALUs. // Stream with AUD NALUs.
std::vector<uint8> stream_; std::vector<uint8> stream_;
@ -140,6 +144,7 @@ class EsParserH264Test : public testing::Test {
protected: protected:
size_t sample_count_; size_t sample_count_;
bool first_frame_is_key_frame_;
}; };
void EsParserH264Test::LoadStream(const char* filename) { void EsParserH264Test::LoadStream(const char* filename) {
@ -204,7 +209,8 @@ TEST_F(EsParserH264Test, OneAccessUnitPerPes) {
// Process each PES packet. // Process each PES packet.
ProcessPesPackets(pes_packets); 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) { TEST_F(EsParserH264Test, NonAlignedPesPacket) {
@ -228,7 +234,8 @@ TEST_F(EsParserH264Test, NonAlignedPesPacket) {
// Process each PES packet. // Process each PES packet.
ProcessPesPackets(pes_packets); 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) { TEST_F(EsParserH264Test, SeveralPesPerAccessUnit) {
@ -258,7 +265,21 @@ TEST_F(EsParserH264Test, SeveralPesPerAccessUnit) {
// Process each PES packet. // Process each PES packet.
ProcessPesPackets(pes_packets); 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<Packet> 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 } // namespace mp2t

View File

@ -75,5 +75,8 @@ bear.h264:
ffmpeg -i bear.mp4 -vcodec copy -vbsf h264_mp4toannexb \ ffmpeg -i bear.mp4 -vcodec copy -vbsf h264_mp4toannexb \
-an bear.h264 -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-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. avc-unit-stream-frame.h264 - Single IDR frame from avc-byte-stream-frame.h264 converted to unit stream format.

Binary file not shown.