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 // DataSourceHost implementation.
28 virtual void SetTotalBytes(int64 total_bytes
) OVERRIDE
{}
29 virtual void AddBufferedByteRange(int64 start
, int64 end
) OVERRIDE
{}
30 virtual void AddBufferedTimeRange(base::TimeDelta start
,
31 base::TimeDelta end
) OVERRIDE
{}
33 // DemuxerHost implementation.
34 virtual void SetDuration(base::TimeDelta duration
) OVERRIDE
{}
35 virtual void OnDemuxerError(media::PipelineStatus error
) OVERRIDE
{}
36 virtual void AddTextStream(media::DemuxerStream
* text_stream
,
37 const media::TextTrackConfig
& config
) OVERRIDE
{}
38 virtual void RemoveTextStream(media::DemuxerStream
* text_stream
) OVERRIDE
{}
41 DISALLOW_COPY_AND_ASSIGN(DemuxerHostImpl
);
44 static void QuitLoopWithStatus(base::MessageLoop
* message_loop
,
45 media::PipelineStatus status
) {
46 CHECK_EQ(status
, media::PIPELINE_OK
);
47 message_loop
->PostTask(FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
50 static void NeedKey(const std::string
& type
,
51 const std::vector
<uint8
>& init_data
) {
52 VLOG(0) << "File is encrypted.";
55 typedef std::vector
<media::DemuxerStream
* > Streams
;
57 // Simulates playback reading requirements by reading from each stream
58 // present in |demuxer| in as-close-to-monotonically-increasing timestamp order.
61 StreamReader(media::Demuxer
* demuxer
, bool enable_bitstream_converter
);
64 // Performs a single step read.
67 // Returns true when all streams have reached end of stream.
70 int number_of_streams() { return static_cast<int>(streams_
.size()); }
71 const Streams
& streams() { return streams_
; }
72 const std::vector
<int>& counts() { return counts_
; }
75 void OnReadDone(base::MessageLoop
* message_loop
,
77 base::TimeDelta
* timestamp
,
78 media::DemuxerStream::Status status
,
79 const scoped_refptr
<media::DecoderBuffer
>& buffer
);
80 int GetNextStreamIndexToRead();
83 std::vector
<bool> end_of_stream_
;
84 std::vector
<base::TimeDelta
> last_read_timestamp_
;
85 std::vector
<int> counts_
;
87 DISALLOW_COPY_AND_ASSIGN(StreamReader
);
90 StreamReader::StreamReader(media::Demuxer
* demuxer
,
91 bool enable_bitstream_converter
) {
92 media::DemuxerStream
* stream
=
93 demuxer
->GetStream(media::DemuxerStream::AUDIO
);
95 streams_
.push_back(stream
);
96 end_of_stream_
.push_back(false);
97 last_read_timestamp_
.push_back(media::kNoTimestamp());
101 stream
= demuxer
->GetStream(media::DemuxerStream::VIDEO
);
103 streams_
.push_back(stream
);
104 end_of_stream_
.push_back(false);
105 last_read_timestamp_
.push_back(media::kNoTimestamp());
106 counts_
.push_back(0);
108 if (enable_bitstream_converter
)
109 stream
->EnableBitstreamConverter();
113 StreamReader::~StreamReader() {}
115 void StreamReader::Read() {
116 int index
= GetNextStreamIndexToRead();
117 bool end_of_stream
= false;
118 base::TimeDelta timestamp
;
120 streams_
[index
]->Read(base::Bind(
121 &StreamReader::OnReadDone
, base::Unretained(this),
122 base::MessageLoop::current(), &end_of_stream
, ×tamp
));
123 base::MessageLoop::current()->Run();
125 CHECK(end_of_stream
|| timestamp
!= media::kNoTimestamp());
126 end_of_stream_
[index
] = end_of_stream
;
127 last_read_timestamp_
[index
] = timestamp
;
131 bool StreamReader::IsDone() {
132 for (size_t i
= 0; i
< end_of_stream_
.size(); ++i
) {
133 if (!end_of_stream_
[i
])
139 void StreamReader::OnReadDone(
140 base::MessageLoop
* message_loop
,
142 base::TimeDelta
* timestamp
,
143 media::DemuxerStream::Status status
,
144 const scoped_refptr
<media::DecoderBuffer
>& buffer
) {
145 CHECK_EQ(status
, media::DemuxerStream::kOk
);
147 *end_of_stream
= buffer
->end_of_stream();
148 *timestamp
= *end_of_stream
? media::kNoTimestamp() : buffer
->timestamp();
149 message_loop
->PostTask(FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
152 int StreamReader::GetNextStreamIndexToRead() {
154 for (int i
= 0; i
< number_of_streams(); ++i
) {
155 // Ignore streams at EOS.
156 if (end_of_stream_
[i
])
159 // Use a stream if it hasn't been read from yet.
160 if (last_read_timestamp_
[i
] == media::kNoTimestamp())
164 last_read_timestamp_
[i
] < last_read_timestamp_
[index
]) {
168 CHECK_GE(index
, 0) << "Couldn't find a stream to read";
172 static void RunDemuxerBenchmark(const std::string
& filename
) {
173 base::FilePath
file_path(GetTestDataFilePath(filename
));
174 double total_time
= 0.0;
175 for (int i
= 0; i
< kBenchmarkIterations
; ++i
) {
177 base::MessageLoop message_loop
;
178 DemuxerHostImpl demuxer_host
;
179 FileDataSource data_source
;
180 ASSERT_TRUE(data_source
.Initialize(file_path
));
182 Demuxer::NeedKeyCB need_key_cb
= base::Bind(&NeedKey
);
183 FFmpegDemuxer
demuxer(message_loop
.message_loop_proxy(),
188 demuxer
.Initialize(&demuxer_host
,
189 base::Bind(&QuitLoopWithStatus
, &message_loop
),
192 StreamReader
stream_reader(&demuxer
, false);
195 base::TimeTicks start
= base::TimeTicks::HighResNow();
196 while (!stream_reader
.IsDone()) {
197 stream_reader
.Read();
199 base::TimeTicks end
= base::TimeTicks::HighResNow();
200 total_time
+= (end
- start
).InSecondsF();
201 demuxer
.Stop(base::Bind(
202 &QuitLoopWithStatus
, &message_loop
, PIPELINE_OK
));
206 perf_test::PrintResult("demuxer_bench",
209 kBenchmarkIterations
/ total_time
,
214 TEST(DemuxerPerfTest
, Demuxer
) {
215 RunDemuxerBenchmark("bear.ogv");
216 RunDemuxerBenchmark("bear-640x360.webm");
217 RunDemuxerBenchmark("sfx_s16le.wav");
218 #if defined(USE_PROPRIETARY_CODECS)
219 RunDemuxerBenchmark("bear-1280x720.mp4");
220 RunDemuxerBenchmark("sfx.mp3");
222 #if defined(OS_CHROMEOS)
223 RunDemuxerBenchmark("bear.flac");
225 #if defined(USE_PROPRIETARY_CODECS) && defined(OS_CHROMEOS)
226 RunDemuxerBenchmark("bear.avi");