1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <sstream>
6#include <string>
7#include <vector>
8
9#include "base/bind.h"
10#include "base/logging.h"
11#include "base/strings/string_util.h"
12#include "base/time/time.h"
13#include "media/base/stream_parser_buffer.h"
14#include "media/base/video_decoder_config.h"
15#include "media/formats/mp2t/es_adapter_video.h"
16#include "testing/gtest/include/gtest/gtest.h"
17
18namespace media {
19namespace mp2t {
20
21namespace {
22
23VideoDecoderConfig CreateFakeVideoConfig() {
24  gfx::Size coded_size(320, 240);
25  gfx::Rect visible_rect(0, 0, 320, 240);
26  gfx::Size natural_size(320, 240);
27  return VideoDecoderConfig(
28      kCodecH264,
29      H264PROFILE_MAIN,
30      VideoFrame::I420,
31      coded_size,
32      visible_rect,
33      natural_size,
34      NULL, 0, false);
35}
36
37StreamParserBuffer::BufferQueue
38GenerateFakeBuffers(const int* frame_pts_ms,
39                    const bool* is_key_frame,
40                    size_t frame_count) {
41  uint8 dummy_buffer[] = {0, 0, 0, 0};
42
43  StreamParserBuffer::BufferQueue buffers(frame_count);
44  for (size_t k = 0; k < frame_count; k++) {
45    buffers[k] = StreamParserBuffer::CopyFrom(
46        dummy_buffer, arraysize(dummy_buffer),
47        is_key_frame[k], DemuxerStream::VIDEO, 0);
48    buffers[k]->set_timestamp(
49        base::TimeDelta::FromMilliseconds(frame_pts_ms[k]));
50  }
51  return buffers;
52}
53
54}
55
56class EsAdapterVideoTest : public testing::Test {
57 public:
58  EsAdapterVideoTest();
59  virtual ~EsAdapterVideoTest() {}
60
61 protected:
62  // Feed the ES adapter with the buffers from |buffer_queue|.
63  // Return the durations computed by the ES adapter as well as
64  // whether each frame emitted by the adapter is a key frame.
65  std::string RunAdapterTest(const StreamParser::BufferQueue& buffer_queue);
66
67 private:
68  void OnNewConfig(const VideoDecoderConfig& video_config);
69  void OnNewBuffer(scoped_refptr<StreamParserBuffer> buffer);
70
71  EsAdapterVideo es_adapter_;
72
73  std::stringstream buffer_descriptors_;
74
75  DISALLOW_COPY_AND_ASSIGN(EsAdapterVideoTest);
76};
77
78EsAdapterVideoTest::EsAdapterVideoTest()
79    : es_adapter_(base::Bind(&EsAdapterVideoTest::OnNewConfig,
80                             base::Unretained(this)),
81                  base::Bind(&EsAdapterVideoTest::OnNewBuffer,
82                             base::Unretained(this))) {
83}
84
85void EsAdapterVideoTest::OnNewConfig(const VideoDecoderConfig& video_config) {
86}
87
88void EsAdapterVideoTest::OnNewBuffer(
89    scoped_refptr<StreamParserBuffer> buffer) {
90  buffer_descriptors_ << "(" << buffer->duration().InMilliseconds() << ","
91                      << (buffer->IsKeyframe() ? "Y" : "N") << ") ";
92}
93
94std::string EsAdapterVideoTest::RunAdapterTest(
95    const StreamParserBuffer::BufferQueue& buffer_queue) {
96  buffer_descriptors_.clear();
97
98  es_adapter_.OnConfigChanged(CreateFakeVideoConfig());
99  for (StreamParserBuffer::BufferQueue::const_iterator it =
100       buffer_queue.begin(); it != buffer_queue.end(); ++it) {
101    es_adapter_.OnNewBuffer(*it);
102  }
103  es_adapter_.Flush();
104
105  std::string s = buffer_descriptors_.str();
106  base::TrimWhitespaceASCII(s, base::TRIM_ALL, &s);
107  return s;
108}
109
110TEST_F(EsAdapterVideoTest, FrameDurationSimpleGop) {
111  // PTS for a GOP without B frames - strictly increasing.
112  int pts_ms[] = {30, 31, 33, 36, 40, 45, 51, 58};
113  bool is_key_frame[] = {
114    true, false, false, false,
115    false, false, false, false };
116  StreamParserBuffer::BufferQueue buffer_queue =
117      GenerateFakeBuffers(pts_ms, is_key_frame, arraysize(pts_ms));
118
119  EXPECT_EQ("(1,Y) (2,N) (3,N) (4,N) (5,N) (6,N) (7,N) (7,N)",
120            RunAdapterTest(buffer_queue));
121}
122
123TEST_F(EsAdapterVideoTest, FrameDurationComplexGop) {
124  // PTS for a GOP with B frames.
125  int pts_ms[] = {30, 120, 60, 90, 210, 150, 180, 300, 240, 270};
126  bool is_key_frame[] = {
127    true, false, false, false, false,
128    false, false, false, false, false };
129  StreamParserBuffer::BufferQueue buffer_queue =
130      GenerateFakeBuffers(pts_ms, is_key_frame, arraysize(pts_ms));
131
132  EXPECT_EQ("(30,Y) (30,N) (30,N) (30,N) (30,N) "
133            "(30,N) (30,N) (30,N) (30,N) (30,N)",
134            RunAdapterTest(buffer_queue));
135}
136
137TEST_F(EsAdapterVideoTest, LeadingNonKeyFrames) {
138  int pts_ms[] = {30, 40, 50, 120, 150, 180};
139  bool is_key_frame[] = {false, false, false, true, false, false};
140  StreamParserBuffer::BufferQueue buffer_queue =
141      GenerateFakeBuffers(pts_ms, is_key_frame, arraysize(pts_ms));
142
143  EXPECT_EQ("(30,Y) (30,Y) (30,Y) (30,Y) (30,N) (30,N)",
144            RunAdapterTest(buffer_queue));
145}
146
147}  // namespace mp2t
148}  // namespace media
149