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
= 100;
22 class DemuxerHostImpl
: public media::DemuxerHost
{
25 ~DemuxerHostImpl() override
{}
27 // DemuxerHost implementation.
28 void AddBufferedTimeRange(base::TimeDelta start
,
29 base::TimeDelta end
) override
{}
30 void SetDuration(base::TimeDelta duration
) override
{}
31 void OnDemuxerError(media::PipelineStatus error
) override
{}
32 void AddTextStream(media::DemuxerStream
* text_stream
,
33 const media::TextTrackConfig
& config
) override
{}
34 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 OnEncryptedMediaInitData(EmeInitDataType init_data_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::EncryptedMediaInitDataCB encrypted_media_init_data_cb
=
179 base::Bind(&OnEncryptedMediaInitData
);
180 FFmpegDemuxer
demuxer(message_loop
.task_runner(), &data_source
,
181 encrypted_media_init_data_cb
, new MediaLog());
183 demuxer
.Initialize(&demuxer_host
,
184 base::Bind(&QuitLoopWithStatus
, &message_loop
),
187 StreamReader
stream_reader(&demuxer
, false);
190 base::TimeTicks start
= base::TimeTicks::Now();
191 while (!stream_reader
.IsDone()) {
192 stream_reader
.Read();
194 base::TimeTicks end
= base::TimeTicks::Now();
195 total_time
+= (end
- start
).InSecondsF();
197 QuitLoopWithStatus(&message_loop
, PIPELINE_OK
);
201 perf_test::PrintResult("demuxer_bench",
204 kBenchmarkIterations
/ total_time
,
210 // http://crbug.com/399002
211 #define MAYBE_Demuxer DISABLED_Demuxer
213 #define MAYBE_Demuxer Demuxer
215 TEST(DemuxerPerfTest
, MAYBE_Demuxer
) {
216 RunDemuxerBenchmark("bear.ogv");
217 RunDemuxerBenchmark("bear-640x360.webm");
218 RunDemuxerBenchmark("sfx_s16le.wav");
219 #if defined(USE_PROPRIETARY_CODECS)
220 RunDemuxerBenchmark("bear-1280x720.mp4");
221 RunDemuxerBenchmark("sfx.mp3");
223 #if defined(OS_CHROMEOS)
224 RunDemuxerBenchmark("bear.flac");
226 #if defined(USE_PROPRIETARY_CODECS) && defined(OS_CHROMEOS)
227 RunDemuxerBenchmark("bear.avi");