1 // Copyright 2013 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.
5 #include "base/at_exit.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/time/time.h"
10 #include "media/base/media.h"
11 #include "media/base/media_log.h"
12 #include "media/base/test_data_util.h"
13 #include "media/filters/ffmpeg_demuxer.h"
14 #include "media/filters/file_data_source.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "testing/perf/perf_test.h"
20 static const int kBenchmarkIterations
= 500;
22 class DemuxerHostImpl
: public media::DemuxerHost
{
25 virtual ~DemuxerHostImpl() {}
27 // DemuxerHost implementation.
28 virtual void AddBufferedTimeRange(base::TimeDelta start
,
29 base::TimeDelta end
) OVERRIDE
{}
30 virtual void SetDuration(base::TimeDelta duration
) OVERRIDE
{}
31 virtual void OnDemuxerError(media::PipelineStatus error
) OVERRIDE
{}
32 virtual void AddTextStream(media::DemuxerStream
* text_stream
,
33 const media::TextTrackConfig
& config
) OVERRIDE
{}
34 virtual void RemoveTextStream(media::DemuxerStream
* text_stream
) OVERRIDE
{}
37 DISALLOW_COPY_AND_ASSIGN(DemuxerHostImpl
);
40 static void QuitLoopWithStatus(base::MessageLoop
* message_loop
,
41 media::PipelineStatus status
) {
42 CHECK_EQ(status
, media::PIPELINE_OK
);
43 message_loop
->PostTask(FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
46 static void NeedKey(const std::string
& type
,
47 const std::vector
<uint8
>& init_data
) {
48 VLOG(0) << "File is encrypted.";
51 typedef std::vector
<media::DemuxerStream
* > Streams
;
53 // Simulates playback reading requirements by reading from each stream
54 // present in |demuxer| in as-close-to-monotonically-increasing timestamp order.
57 StreamReader(media::Demuxer
* demuxer
, bool enable_bitstream_converter
);
60 // Performs a single step read.
63 // Returns true when all streams have reached end of stream.
66 int number_of_streams() { return static_cast<int>(streams_
.size()); }
67 const Streams
& streams() { return streams_
; }
68 const std::vector
<int>& counts() { return counts_
; }
71 void OnReadDone(base::MessageLoop
* message_loop
,
73 base::TimeDelta
* timestamp
,
74 media::DemuxerStream::Status status
,
75 const scoped_refptr
<media::DecoderBuffer
>& buffer
);
76 int GetNextStreamIndexToRead();
79 std::vector
<bool> end_of_stream_
;
80 std::vector
<base::TimeDelta
> last_read_timestamp_
;
81 std::vector
<int> counts_
;
83 DISALLOW_COPY_AND_ASSIGN(StreamReader
);
86 StreamReader::StreamReader(media::Demuxer
* demuxer
,
87 bool enable_bitstream_converter
) {
88 media::DemuxerStream
* stream
=
89 demuxer
->GetStream(media::DemuxerStream::AUDIO
);
91 streams_
.push_back(stream
);
92 end_of_stream_
.push_back(false);
93 last_read_timestamp_
.push_back(media::kNoTimestamp());
97 stream
= demuxer
->GetStream(media::DemuxerStream::VIDEO
);
99 streams_
.push_back(stream
);
100 end_of_stream_
.push_back(false);
101 last_read_timestamp_
.push_back(media::kNoTimestamp());
102 counts_
.push_back(0);
104 if (enable_bitstream_converter
)
105 stream
->EnableBitstreamConverter();
109 StreamReader::~StreamReader() {}
111 void StreamReader::Read() {
112 int index
= GetNextStreamIndexToRead();
113 bool end_of_stream
= false;
114 base::TimeDelta timestamp
;
116 streams_
[index
]->Read(base::Bind(
117 &StreamReader::OnReadDone
, base::Unretained(this),
118 base::MessageLoop::current(), &end_of_stream
, ×tamp
));
119 base::MessageLoop::current()->Run();
121 CHECK(end_of_stream
|| timestamp
!= media::kNoTimestamp());
122 end_of_stream_
[index
] = end_of_stream
;
123 last_read_timestamp_
[index
] = timestamp
;
127 bool StreamReader::IsDone() {
128 for (size_t i
= 0; i
< end_of_stream_
.size(); ++i
) {
129 if (!end_of_stream_
[i
])
135 void StreamReader::OnReadDone(
136 base::MessageLoop
* message_loop
,
138 base::TimeDelta
* timestamp
,
139 media::DemuxerStream::Status status
,
140 const scoped_refptr
<media::DecoderBuffer
>& buffer
) {
141 CHECK_EQ(status
, media::DemuxerStream::kOk
);
143 *end_of_stream
= buffer
->end_of_stream();
144 *timestamp
= *end_of_stream
? media::kNoTimestamp() : buffer
->timestamp();
145 message_loop
->PostTask(FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
148 int StreamReader::GetNextStreamIndexToRead() {
150 for (int i
= 0; i
< number_of_streams(); ++i
) {
151 // Ignore streams at EOS.
152 if (end_of_stream_
[i
])
155 // Use a stream if it hasn't been read from yet.
156 if (last_read_timestamp_
[i
] == media::kNoTimestamp())
160 last_read_timestamp_
[i
] < last_read_timestamp_
[index
]) {
164 CHECK_GE(index
, 0) << "Couldn't find a stream to read";
168 static void RunDemuxerBenchmark(const std::string
& filename
) {
169 base::FilePath
file_path(GetTestDataFilePath(filename
));
170 double total_time
= 0.0;
171 for (int i
= 0; i
< kBenchmarkIterations
; ++i
) {
173 base::MessageLoop message_loop
;
174 DemuxerHostImpl demuxer_host
;
175 FileDataSource data_source
;
176 ASSERT_TRUE(data_source
.Initialize(file_path
));
178 Demuxer::NeedKeyCB need_key_cb
= base::Bind(&NeedKey
);
179 FFmpegDemuxer
demuxer(message_loop
.message_loop_proxy(),
184 demuxer
.Initialize(&demuxer_host
,
185 base::Bind(&QuitLoopWithStatus
, &message_loop
),
188 StreamReader
stream_reader(&demuxer
, false);
191 base::TimeTicks start
= base::TimeTicks::HighResNow();
192 while (!stream_reader
.IsDone()) {
193 stream_reader
.Read();
195 base::TimeTicks end
= base::TimeTicks::HighResNow();
196 total_time
+= (end
- start
).InSecondsF();
197 demuxer
.Stop(base::Bind(
198 &QuitLoopWithStatus
, &message_loop
, PIPELINE_OK
));
202 perf_test::PrintResult("demuxer_bench",
205 kBenchmarkIterations
/ total_time
,
210 TEST(DemuxerPerfTest
, Demuxer
) {
211 RunDemuxerBenchmark("bear.ogv");
212 RunDemuxerBenchmark("bear-640x360.webm");
213 RunDemuxerBenchmark("sfx_s16le.wav");
214 #if defined(USE_PROPRIETARY_CODECS)
215 RunDemuxerBenchmark("bear-1280x720.mp4");
216 RunDemuxerBenchmark("sfx.mp3");
218 #if defined(OS_CHROMEOS)
219 RunDemuxerBenchmark("bear.flac");
221 #if defined(USE_PROPRIETARY_CODECS) && defined(OS_CHROMEOS)
222 RunDemuxerBenchmark("bear.avi");