// Copyright 2014 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 #include #include #include "base/bind.h" #include "base/logging.h" #include "base/strings/string_util.h" #include "base/time/time.h" #include "media/base/stream_parser_buffer.h" #include "media/base/video_decoder_config.h" #include "media/formats/mp2t/es_adapter_video.h" #include "testing/gtest/include/gtest/gtest.h" namespace media { namespace mp2t { namespace { VideoDecoderConfig CreateFakeVideoConfig() { gfx::Size coded_size(320, 240); gfx::Rect visible_rect(0, 0, 320, 240); gfx::Size natural_size(320, 240); return VideoDecoderConfig( kCodecH264, H264PROFILE_MAIN, VideoFrame::I420, coded_size, visible_rect, natural_size, NULL, 0, false); } StreamParserBuffer::BufferQueue GenerateFakeBuffers(const int* frame_pts_ms, const bool* is_key_frame, size_t frame_count) { uint8 dummy_buffer[] = {0, 0, 0, 0}; StreamParserBuffer::BufferQueue buffers(frame_count); for (size_t k = 0; k < frame_count; k++) { buffers[k] = StreamParserBuffer::CopyFrom( dummy_buffer, arraysize(dummy_buffer), is_key_frame[k], DemuxerStream::VIDEO, 0); buffers[k]->set_timestamp( base::TimeDelta::FromMilliseconds(frame_pts_ms[k])); } return buffers; } } class EsAdapterVideoTest : public testing::Test { public: EsAdapterVideoTest(); virtual ~EsAdapterVideoTest() {} protected: // Feed the ES adapter with the buffers from |buffer_queue|. // Return the durations computed by the ES adapter as well as // whether each frame emitted by the adapter is a key frame. std::string RunAdapterTest(const StreamParser::BufferQueue& buffer_queue); private: void OnNewConfig(const VideoDecoderConfig& video_config); void OnNewBuffer(scoped_refptr buffer); EsAdapterVideo es_adapter_; std::stringstream buffer_descriptors_; DISALLOW_COPY_AND_ASSIGN(EsAdapterVideoTest); }; EsAdapterVideoTest::EsAdapterVideoTest() : es_adapter_(base::Bind(&EsAdapterVideoTest::OnNewConfig, base::Unretained(this)), base::Bind(&EsAdapterVideoTest::OnNewBuffer, base::Unretained(this))) { } void EsAdapterVideoTest::OnNewConfig(const VideoDecoderConfig& video_config) { } void EsAdapterVideoTest::OnNewBuffer( scoped_refptr buffer) { buffer_descriptors_ << "(" << buffer->duration().InMilliseconds() << "," << (buffer->IsKeyframe() ? "Y" : "N") << ") "; } std::string EsAdapterVideoTest::RunAdapterTest( const StreamParserBuffer::BufferQueue& buffer_queue) { buffer_descriptors_.clear(); es_adapter_.OnConfigChanged(CreateFakeVideoConfig()); for (StreamParserBuffer::BufferQueue::const_iterator it = buffer_queue.begin(); it != buffer_queue.end(); ++it) { es_adapter_.OnNewBuffer(*it); } es_adapter_.Flush(); std::string s = buffer_descriptors_.str(); base::TrimWhitespaceASCII(s, base::TRIM_ALL, &s); return s; } TEST_F(EsAdapterVideoTest, FrameDurationSimpleGop) { // PTS for a GOP without B frames - strictly increasing. int pts_ms[] = {30, 31, 33, 36, 40, 45, 51, 58}; bool is_key_frame[] = { true, false, false, false, false, false, false, false }; StreamParserBuffer::BufferQueue buffer_queue = GenerateFakeBuffers(pts_ms, is_key_frame, arraysize(pts_ms)); EXPECT_EQ("(1,Y) (2,N) (3,N) (4,N) (5,N) (6,N) (7,N) (7,N)", RunAdapterTest(buffer_queue)); } TEST_F(EsAdapterVideoTest, FrameDurationComplexGop) { // PTS for a GOP with B frames. int pts_ms[] = {30, 120, 60, 90, 210, 150, 180, 300, 240, 270}; bool is_key_frame[] = { true, false, false, false, false, false, false, false, false, false }; StreamParserBuffer::BufferQueue buffer_queue = GenerateFakeBuffers(pts_ms, is_key_frame, arraysize(pts_ms)); EXPECT_EQ("(30,Y) (30,N) (30,N) (30,N) (30,N) " "(30,N) (30,N) (30,N) (30,N) (30,N)", RunAdapterTest(buffer_queue)); } TEST_F(EsAdapterVideoTest, LeadingNonKeyFrames) { int pts_ms[] = {30, 40, 50, 120, 150, 180}; bool is_key_frame[] = {false, false, false, true, false, false}; StreamParserBuffer::BufferQueue buffer_queue = GenerateFakeBuffers(pts_ms, is_key_frame, arraysize(pts_ms)); EXPECT_EQ("(30,Y) (30,Y) (30,Y) (30,Y) (30,N) (30,N)", RunAdapterTest(buffer_queue)); } } // namespace mp2t } // namespace media