123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- // Copyright 2013 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include <stddef.h>
- #include <stdint.h>
- #include <memory>
- #include "base/at_exit.h"
- #include "base/bind.h"
- #include "base/run_loop.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/test/task_environment.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "base/time/time.h"
- #include "build/build_config.h"
- #include "media/base/media.h"
- #include "media/base/media_tracks.h"
- #include "media/base/media_util.h"
- #include "media/base/test_data_util.h"
- #include "media/base/timestamp_constants.h"
- #include "media/filters/ffmpeg_demuxer.h"
- #include "media/filters/file_data_source.h"
- #include "media/media_buildflags.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "testing/perf/perf_result_reporter.h"
- namespace media {
- static const int kBenchmarkIterations = 100;
- class DemuxerHostImpl : public media::DemuxerHost {
- public:
- DemuxerHostImpl() = default;
- DemuxerHostImpl(const DemuxerHostImpl&) = delete;
- DemuxerHostImpl& operator=(const DemuxerHostImpl&) = delete;
- ~DemuxerHostImpl() override = default;
- // DemuxerHost implementation.
- void OnBufferedTimeRangesChanged(
- const Ranges<base::TimeDelta>& ranges) override {}
- void SetDuration(base::TimeDelta duration) override {}
- void OnDemuxerError(media::PipelineStatus error) override {}
- };
- static void QuitLoopWithStatus(base::OnceClosure quit_cb,
- media::PipelineStatus status) {
- CHECK_EQ(status, media::PIPELINE_OK);
- std::move(quit_cb).Run();
- }
- static void OnEncryptedMediaInitData(EmeInitDataType init_data_type,
- const std::vector<uint8_t>& init_data) {
- DVLOG(1) << "File is encrypted.";
- }
- static void OnMediaTracksUpdated(std::unique_ptr<MediaTracks> tracks) {
- DVLOG(1) << "Got media tracks info, tracks = " << tracks->tracks().size();
- }
- typedef std::vector<media::DemuxerStream*> Streams;
- // Simulates playback reading requirements by reading from each stream
- // present in |demuxer| in as-close-to-monotonically-increasing timestamp order.
- class StreamReader {
- public:
- StreamReader(media::Demuxer* demuxer, bool enable_bitstream_converter);
- StreamReader(const StreamReader&) = delete;
- StreamReader& operator=(const StreamReader&) = delete;
- ~StreamReader();
- // Performs a single step read.
- void Read();
- // Returns true when all streams have reached end of stream.
- bool IsDone();
- int number_of_streams() { return static_cast<int>(streams_.size()); }
- const Streams& streams() { return streams_; }
- const std::vector<int>& counts() { return counts_; }
- private:
- void OnReadDone(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- base::OnceClosure quit_when_idle_closure,
- bool* end_of_stream,
- base::TimeDelta* timestamp,
- media::DemuxerStream::Status status,
- scoped_refptr<DecoderBuffer> buffer);
- int GetNextStreamIndexToRead();
- Streams streams_;
- std::vector<bool> end_of_stream_;
- std::vector<base::TimeDelta> last_read_timestamp_;
- std::vector<int> counts_;
- };
- StreamReader::StreamReader(media::Demuxer* demuxer,
- bool enable_bitstream_converter) {
- std::vector<media::DemuxerStream*> streams = demuxer->GetAllStreams();
- for (auto* stream : streams) {
- streams_.push_back(stream);
- end_of_stream_.push_back(false);
- last_read_timestamp_.push_back(media::kNoTimestamp);
- counts_.push_back(0);
- if (enable_bitstream_converter && stream->type() == DemuxerStream::VIDEO)
- stream->EnableBitstreamConverter();
- }
- }
- StreamReader::~StreamReader() = default;
- void StreamReader::Read() {
- int index = GetNextStreamIndexToRead();
- bool end_of_stream = false;
- base::TimeDelta timestamp;
- base::RunLoop run_loop;
- streams_[index]->Read(base::BindOnce(
- &StreamReader::OnReadDone, base::Unretained(this),
- base::ThreadTaskRunnerHandle::Get(), run_loop.QuitWhenIdleClosure(),
- &end_of_stream, ×tamp));
- run_loop.Run();
- CHECK(end_of_stream || timestamp != media::kNoTimestamp);
- end_of_stream_[index] = end_of_stream;
- last_read_timestamp_[index] = timestamp;
- counts_[index]++;
- }
- bool StreamReader::IsDone() {
- for (size_t i = 0; i < end_of_stream_.size(); ++i) {
- if (!end_of_stream_[i])
- return false;
- }
- return true;
- }
- void StreamReader::OnReadDone(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- base::OnceClosure quit_when_idle_closure,
- bool* end_of_stream,
- base::TimeDelta* timestamp,
- media::DemuxerStream::Status status,
- scoped_refptr<DecoderBuffer> buffer) {
- CHECK_EQ(status, media::DemuxerStream::kOk);
- CHECK(buffer);
- *end_of_stream = buffer->end_of_stream();
- *timestamp = *end_of_stream ? media::kNoTimestamp : buffer->timestamp();
- task_runner->PostTask(FROM_HERE, std::move(quit_when_idle_closure));
- }
- int StreamReader::GetNextStreamIndexToRead() {
- int index = -1;
- for (int i = 0; i < number_of_streams(); ++i) {
- // Ignore streams at EOS.
- if (end_of_stream_[i])
- continue;
- // Use a stream if it hasn't been read from yet.
- if (last_read_timestamp_[i] == media::kNoTimestamp)
- return i;
- if (index < 0 || last_read_timestamp_[i] < last_read_timestamp_[index]) {
- index = i;
- }
- }
- CHECK_GE(index, 0) << "Couldn't find a stream to read";
- return index;
- }
- static void RunDemuxerBenchmark(const std::string& filename) {
- base::FilePath file_path(GetTestDataFilePath(filename));
- base::TimeDelta total_time;
- NullMediaLog media_log_;
- for (int i = 0; i < kBenchmarkIterations; ++i) {
- // Setup.
- base::test::TaskEnvironment task_environment_;
- DemuxerHostImpl demuxer_host;
- FileDataSource data_source;
- ASSERT_TRUE(data_source.Initialize(file_path));
- Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
- base::BindRepeating(&OnEncryptedMediaInitData);
- Demuxer::MediaTracksUpdatedCB tracks_updated_cb =
- base::BindRepeating(&OnMediaTracksUpdated);
- FFmpegDemuxer demuxer(base::ThreadTaskRunnerHandle::Get(), &data_source,
- encrypted_media_init_data_cb, tracks_updated_cb,
- &media_log_, true);
- {
- base::RunLoop run_loop;
- demuxer.Initialize(&demuxer_host, base::BindOnce(&QuitLoopWithStatus,
- run_loop.QuitClosure()));
- run_loop.Run();
- }
- StreamReader stream_reader(&demuxer, false);
- // Benchmark.
- base::TimeTicks start = base::TimeTicks::Now();
- while (!stream_reader.IsDone())
- stream_reader.Read();
- total_time += base::TimeTicks::Now() - start;
- demuxer.Stop();
- base::RunLoop().RunUntilIdle();
- }
- perf_test::PerfResultReporter reporter("demuxer_bench", filename);
- reporter.RegisterImportantMetric("", "runs/s");
- reporter.AddResult("", kBenchmarkIterations / total_time.InSecondsF());
- }
- class DemuxerPerfTest : public testing::TestWithParam<const char*> {};
- TEST_P(DemuxerPerfTest, Demuxer) {
- RunDemuxerBenchmark(GetParam());
- }
- static const char* kDemuxerTestFiles[] {
- "bear.ogv", "bear-640x360.webm", "sfx.mp3",
- #if BUILDFLAG(USE_PROPRIETARY_CODECS)
- "bear-1280x720.mp4",
- #endif
- };
- // For simplicity we only test containers with above 2% daily usage as measured
- // by the Media.DetectedContainer histogram.
- INSTANTIATE_TEST_SUITE_P(
- All,
- DemuxerPerfTest,
- testing::ValuesIn(kDemuxerTestFiles));
- } // namespace media
|