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/base/timestamp_constants.h"
14 #include "media/filters/ffmpeg_demuxer.h"
15 #include "media/filters/file_data_source.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "testing/perf/perf_test.h"
21 static const int kBenchmarkIterations
= 100;
23 class DemuxerHostImpl
: public media::DemuxerHost
{
26 ~DemuxerHostImpl() override
{}
28 // DemuxerHost implementation.
29 void AddBufferedTimeRange(base::TimeDelta start
,
30 base::TimeDelta end
) override
{}
31 void SetDuration(base::TimeDelta duration
) override
{}
32 void OnDemuxerError(media::PipelineStatus error
) override
{}
33 void AddTextStream(media::DemuxerStream
* text_stream
,
34 const media::TextTrackConfig
& config
) override
{}
35 void RemoveTextStream(media::DemuxerStream
* text_stream
) override
{}
38 DISALLOW_COPY_AND_ASSIGN(DemuxerHostImpl
);
41 static void QuitLoopWithStatus(base::MessageLoop
* message_loop
,
42 media::PipelineStatus status
) {
43 CHECK_EQ(status
, media::PIPELINE_OK
);
44 message_loop
->PostTask(FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
47 static void OnEncryptedMediaInitData(EmeInitDataType init_data_type
,
48 const std::vector
<uint8
>& init_data
) {
49 VLOG(0) << "File is encrypted.";
52 typedef std::vector
<media::DemuxerStream
* > Streams
;
54 // Simulates playback reading requirements by reading from each stream
55 // present in |demuxer| in as-close-to-monotonically-increasing timestamp order.
58 StreamReader(media::Demuxer
* demuxer
, bool enable_bitstream_converter
);
61 // Performs a single step read.
64 // Returns true when all streams have reached end of stream.
67 int number_of_streams() { return static_cast<int>(streams_
.size()); }
68 const Streams
& streams() { return streams_
; }
69 const std::vector
<int>& counts() { return counts_
; }
72 void OnReadDone(base::MessageLoop
* message_loop
,
74 base::TimeDelta
* timestamp
,
75 media::DemuxerStream::Status status
,
76 const scoped_refptr
<media::DecoderBuffer
>& buffer
);
77 int GetNextStreamIndexToRead();
80 std::vector
<bool> end_of_stream_
;
81 std::vector
<base::TimeDelta
> last_read_timestamp_
;
82 std::vector
<int> counts_
;
84 DISALLOW_COPY_AND_ASSIGN(StreamReader
);
87 StreamReader::StreamReader(media::Demuxer
* demuxer
,
88 bool enable_bitstream_converter
) {
89 media::DemuxerStream
* stream
=
90 demuxer
->GetStream(media::DemuxerStream::AUDIO
);
92 streams_
.push_back(stream
);
93 end_of_stream_
.push_back(false);
94 last_read_timestamp_
.push_back(media::kNoTimestamp());
98 stream
= demuxer
->GetStream(media::DemuxerStream::VIDEO
);
100 streams_
.push_back(stream
);
101 end_of_stream_
.push_back(false);
102 last_read_timestamp_
.push_back(media::kNoTimestamp());
103 counts_
.push_back(0);
105 if (enable_bitstream_converter
)
106 stream
->EnableBitstreamConverter();
110 StreamReader::~StreamReader() {}
112 void StreamReader::Read() {
113 int index
= GetNextStreamIndexToRead();
114 bool end_of_stream
= false;
115 base::TimeDelta timestamp
;
117 streams_
[index
]->Read(base::Bind(
118 &StreamReader::OnReadDone
, base::Unretained(this),
119 base::MessageLoop::current(), &end_of_stream
, ×tamp
));
120 base::MessageLoop::current()->Run();
122 CHECK(end_of_stream
|| timestamp
!= media::kNoTimestamp());
123 end_of_stream_
[index
] = end_of_stream
;
124 last_read_timestamp_
[index
] = timestamp
;
128 bool StreamReader::IsDone() {
129 for (size_t i
= 0; i
< end_of_stream_
.size(); ++i
) {
130 if (!end_of_stream_
[i
])
136 void StreamReader::OnReadDone(
137 base::MessageLoop
* message_loop
,
139 base::TimeDelta
* timestamp
,
140 media::DemuxerStream::Status status
,
141 const scoped_refptr
<media::DecoderBuffer
>& buffer
) {
142 CHECK_EQ(status
, media::DemuxerStream::kOk
);
144 *end_of_stream
= buffer
->end_of_stream();
145 *timestamp
= *end_of_stream
? media::kNoTimestamp() : buffer
->timestamp();
146 message_loop
->PostTask(FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
149 int StreamReader::GetNextStreamIndexToRead() {
151 for (int i
= 0; i
< number_of_streams(); ++i
) {
152 // Ignore streams at EOS.
153 if (end_of_stream_
[i
])
156 // Use a stream if it hasn't been read from yet.
157 if (last_read_timestamp_
[i
] == media::kNoTimestamp())
161 last_read_timestamp_
[i
] < last_read_timestamp_
[index
]) {
165 CHECK_GE(index
, 0) << "Couldn't find a stream to read";
169 static void RunDemuxerBenchmark(const std::string
& filename
) {
170 base::FilePath
file_path(GetTestDataFilePath(filename
));
171 double total_time
= 0.0;
172 for (int i
= 0; i
< kBenchmarkIterations
; ++i
) {
174 base::MessageLoop message_loop
;
175 DemuxerHostImpl demuxer_host
;
176 FileDataSource data_source
;
177 ASSERT_TRUE(data_source
.Initialize(file_path
));
179 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb
=
180 base::Bind(&OnEncryptedMediaInitData
);
181 FFmpegDemuxer
demuxer(message_loop
.task_runner(), &data_source
,
182 encrypted_media_init_data_cb
, new MediaLog());
184 demuxer
.Initialize(&demuxer_host
,
185 base::Bind(&QuitLoopWithStatus
, &message_loop
),
188 StreamReader
stream_reader(&demuxer
, false);
191 base::TimeTicks start
= base::TimeTicks::Now();
192 while (!stream_reader
.IsDone()) {
193 stream_reader
.Read();
195 base::TimeTicks end
= base::TimeTicks::Now();
196 total_time
+= (end
- start
).InSecondsF();
198 QuitLoopWithStatus(&message_loop
, PIPELINE_OK
);
202 perf_test::PrintResult("demuxer_bench",
205 kBenchmarkIterations
/ total_time
,
211 // http://crbug.com/399002
212 #define MAYBE_Demuxer DISABLED_Demuxer
214 #define MAYBE_Demuxer Demuxer
216 TEST(DemuxerPerfTest
, MAYBE_Demuxer
) {
217 RunDemuxerBenchmark("bear.ogv");
218 RunDemuxerBenchmark("bear-640x360.webm");
219 RunDemuxerBenchmark("sfx_s16le.wav");
220 #if defined(USE_PROPRIETARY_CODECS)
221 RunDemuxerBenchmark("bear-1280x720.mp4");
222 RunDemuxerBenchmark("sfx.mp3");
224 #if defined(OS_CHROMEOS)
225 RunDemuxerBenchmark("bear.flac");
227 #if defined(USE_PROPRIETARY_CODECS) && defined(OS_CHROMEOS)
228 RunDemuxerBenchmark("bear.avi");