[M120 Migration][hbbtv] Audio tracks count notification
[platform/framework/web/chromium-efl.git] / media / filters / demuxer_perftest.cc
1 // Copyright 2013 The Chromium Authors
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 <stddef.h>
6 #include <stdint.h>
7 #include <memory>
8
9 #include "base/at_exit.h"
10 #include "base/functional/bind.h"
11 #include "base/run_loop.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/task/single_thread_task_runner.h"
14 #include "base/test/task_environment.h"
15 #include "base/time/time.h"
16 #include "build/build_config.h"
17 #include "media/base/media.h"
18 #include "media/base/media_tracks.h"
19 #include "media/base/media_util.h"
20 #include "media/base/test_data_util.h"
21 #include "media/base/timestamp_constants.h"
22 #include "media/filters/ffmpeg_demuxer.h"
23 #include "media/filters/file_data_source.h"
24 #include "media/media_buildflags.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 #include "testing/perf/perf_result_reporter.h"
27
28 namespace media {
29
30 static const int kBenchmarkIterations = 100;
31
32 class DemuxerHostImpl : public media::DemuxerHost {
33  public:
34   DemuxerHostImpl() = default;
35
36   DemuxerHostImpl(const DemuxerHostImpl&) = delete;
37   DemuxerHostImpl& operator=(const DemuxerHostImpl&) = delete;
38
39   ~DemuxerHostImpl() override = default;
40
41   // DemuxerHost implementation.
42   void OnBufferedTimeRangesChanged(
43       const Ranges<base::TimeDelta>& ranges) override {}
44   void SetDuration(base::TimeDelta duration) override {}
45   void OnDemuxerError(media::PipelineStatus error) override {}
46 };
47
48 static void QuitLoopWithStatus(base::OnceClosure quit_cb,
49                                media::PipelineStatus status) {
50   CHECK_EQ(status, media::PIPELINE_OK);
51   std::move(quit_cb).Run();
52 }
53
54 static void OnEncryptedMediaInitData(EmeInitDataType init_data_type,
55                                      const std::vector<uint8_t>& init_data) {
56   DVLOG(1) << "File is encrypted.";
57 }
58
59 static void OnMediaTracksUpdated(std::unique_ptr<MediaTracks> tracks) {
60   DVLOG(1) << "Got media tracks info, tracks = " << tracks->tracks().size();
61 }
62
63 typedef std::vector<media::DemuxerStream*> Streams;
64
65 // Simulates playback reading requirements by reading from each stream
66 // present in |demuxer| in as-close-to-monotonically-increasing timestamp order.
67 class StreamReader {
68  public:
69   StreamReader(media::Demuxer* demuxer, bool enable_bitstream_converter);
70
71   StreamReader(const StreamReader&) = delete;
72   StreamReader& operator=(const StreamReader&) = delete;
73
74   ~StreamReader();
75
76   // Performs a single step read.
77   void Read();
78
79   // Returns true when all streams have reached end of stream.
80   bool IsDone();
81
82   int number_of_streams() { return static_cast<int>(streams_.size()); }
83   const Streams& streams() { return streams_; }
84   const std::vector<int>& counts() { return counts_; }
85
86  private:
87   void OnReadDone(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
88                   base::OnceClosure quit_when_idle_closure,
89                   bool* end_of_stream,
90                   base::TimeDelta* timestamp,
91                   media::DemuxerStream::Status status,
92                   DemuxerStream::DecoderBufferVector buffers);
93   int GetNextStreamIndexToRead();
94
95   Streams streams_;
96   std::vector<bool> end_of_stream_;
97   std::vector<base::TimeDelta> last_read_timestamp_;
98   std::vector<int> counts_;
99 };
100
101 StreamReader::StreamReader(media::Demuxer* demuxer,
102                            bool enable_bitstream_converter) {
103   std::vector<media::DemuxerStream*> streams = demuxer->GetAllStreams();
104   for (auto* stream : streams) {
105     streams_.push_back(stream);
106     end_of_stream_.push_back(false);
107     last_read_timestamp_.push_back(media::kNoTimestamp);
108     counts_.push_back(0);
109     if (enable_bitstream_converter && stream->type() == DemuxerStream::VIDEO)
110       stream->EnableBitstreamConverter();
111   }
112 }
113
114 StreamReader::~StreamReader() = default;
115
116 void StreamReader::Read() {
117   int index = GetNextStreamIndexToRead();
118   bool end_of_stream = false;
119   base::TimeDelta timestamp;
120
121   base::RunLoop run_loop;
122   streams_[index]->Read(
123       1, base::BindOnce(&StreamReader::OnReadDone, base::Unretained(this),
124                         base::SingleThreadTaskRunner::GetCurrentDefault(),
125                         run_loop.QuitWhenIdleClosure(), &end_of_stream,
126                         &timestamp));
127   run_loop.Run();
128
129   CHECK(end_of_stream || timestamp != media::kNoTimestamp);
130   end_of_stream_[index] = end_of_stream;
131   last_read_timestamp_[index] = timestamp;
132   counts_[index]++;
133 }
134
135 bool StreamReader::IsDone() {
136   for (size_t i = 0; i < end_of_stream_.size(); ++i) {
137     if (!end_of_stream_[i])
138       return false;
139   }
140   return true;
141 }
142
143 void StreamReader::OnReadDone(
144     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
145     base::OnceClosure quit_when_idle_closure,
146     bool* end_of_stream,
147     base::TimeDelta* timestamp,
148     media::DemuxerStream::Status status,
149     DemuxerStream::DecoderBufferVector buffers) {
150   CHECK_EQ(status, media::DemuxerStream::kOk);
151   CHECK_EQ(buffers.size(), 1u) << "StreamReader only reads a single-buffer.";
152   scoped_refptr<DecoderBuffer> buffer = std::move(buffers[0]);
153   *end_of_stream = buffer->end_of_stream();
154   *timestamp = *end_of_stream ? media::kNoTimestamp : buffer->timestamp();
155   task_runner->PostTask(FROM_HERE, std::move(quit_when_idle_closure));
156 }
157
158 int StreamReader::GetNextStreamIndexToRead() {
159   int index = -1;
160   for (int i = 0; i < number_of_streams(); ++i) {
161     // Ignore streams at EOS.
162     if (end_of_stream_[i])
163       continue;
164
165     // Use a stream if it hasn't been read from yet.
166     if (last_read_timestamp_[i] == media::kNoTimestamp)
167       return i;
168
169     if (index < 0 || last_read_timestamp_[i] < last_read_timestamp_[index]) {
170       index = i;
171     }
172   }
173   CHECK_GE(index, 0) << "Couldn't find a stream to read";
174   return index;
175 }
176
177 static void RunDemuxerBenchmark(const std::string& filename) {
178   base::FilePath file_path(GetTestDataFilePath(filename));
179   base::TimeDelta total_time;
180   NullMediaLog media_log_;
181   for (int i = 0; i < kBenchmarkIterations; ++i) {
182     // Setup.
183     base::test::TaskEnvironment task_environment_;
184     DemuxerHostImpl demuxer_host;
185     FileDataSource data_source;
186     ASSERT_TRUE(data_source.Initialize(file_path));
187
188     Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
189         base::BindRepeating(&OnEncryptedMediaInitData);
190     Demuxer::MediaTracksUpdatedCB tracks_updated_cb =
191         base::BindRepeating(&OnMediaTracksUpdated);
192     FFmpegDemuxer demuxer(base::SingleThreadTaskRunner::GetCurrentDefault(),
193                           &data_source, encrypted_media_init_data_cb,
194                           tracks_updated_cb, &media_log_, true);
195
196     {
197       base::RunLoop run_loop;
198       demuxer.Initialize(&demuxer_host, base::BindOnce(&QuitLoopWithStatus,
199                                                        run_loop.QuitClosure()));
200       run_loop.Run();
201     }
202
203     StreamReader stream_reader(&demuxer, false);
204
205     // Benchmark.
206     base::TimeTicks start = base::TimeTicks::Now();
207     while (!stream_reader.IsDone())
208       stream_reader.Read();
209     total_time += base::TimeTicks::Now() - start;
210     demuxer.Stop();
211     base::RunLoop().RunUntilIdle();
212   }
213
214   perf_test::PerfResultReporter reporter("demuxer_bench", filename);
215   reporter.RegisterImportantMetric("", "runs/s");
216   reporter.AddResult("", kBenchmarkIterations / total_time.InSecondsF());
217 }
218
219 class DemuxerPerfTest : public testing::TestWithParam<const char*> {};
220
221 TEST_P(DemuxerPerfTest, Demuxer) {
222   RunDemuxerBenchmark(GetParam());
223 }
224
225 static const char* kDemuxerTestFiles[] {
226   "bear.ogv", "bear-640x360.webm", "sfx.mp3",
227 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
228       "bear-1280x720.mp4",
229 #endif
230 };
231
232 // For simplicity we only test containers with above 2% daily usage as measured
233 // by the Media.DetectedContainer histogram.
234 INSTANTIATE_TEST_SUITE_P(
235     All,
236     DemuxerPerfTest,
237     testing::ValuesIn(kDemuxerTestFiles));
238
239 }  // namespace media