demuxer_perftest.cc 7.5 KB

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