Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(45)

Unified Diff: examples/media_test/media_test_app.cc

Issue 1809703003: Motown: Add examples/media_test, a command line media player app. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Tweaks based on feedback. Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: examples/media_test/media_test_app.cc
diff --git a/examples/media_test/media_test_app.cc b/examples/media_test/media_test_app.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b916f6199900558563e92b606492f2179327c75a
--- /dev/null
+++ b/examples/media_test/media_test_app.cc
@@ -0,0 +1,332 @@
+// Copyright 2015 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 <deque>
+#include <iomanip>
+#include <iostream>
+
+#include "base/bind.h"
+#include "examples/media_test/keystroke.h"
+#include "examples/media_test/media_test.h"
+#include "mojo/application/application_runner_chromium.h"
+#include "mojo/public/c/system/main.h"
+#include "mojo/public/cpp/application/application_connection.h"
+#include "mojo/public/cpp/application/application_delegate.h"
+#include "mojo/public/cpp/application/application_impl.h"
+
+namespace mojo {
+namespace media {
+namespace examples {
+
+class MediaTestApp : public mojo::ApplicationDelegate {
+ public:
+ MediaTestApp() {}
+
+ ~MediaTestApp() override {}
+
+ // ApplicationDelegate implementation.
+ void Initialize(mojo::ApplicationImpl* app) override {
+ app_ = app;
+ ProcessArgs(app->args());
+
+ std::cout << std::endl << "MEDIA TEST" << std::endl << std::endl;
+
+ if (input_file_names_.empty()) {
+ std::cout << "Please provide the names of the files you want to play;"
+ << " for example:" << std::endl;
+ std::cout << "mojo/devtools/common/mojo_run \\" << std::endl;
+ std::cout << " \"https://core.mojoapps.io/media_test.mojo \\"
+ << std::endl;
+ std::cout << " file:///usr/local/google/home/you/superstition.ogg \\"
+ << std::endl;
+ std::cout << " file:///usr/local/google/home/you/higherground.ogg\""
+ << std::endl << std::endl;
+ base::MessageLoop::current()->Quit();
+ return;
+ }
+
+ std::cout << " <enter> play/pause" << std::endl;
+ std::cout << " n<enter> next file" << std::endl;
+ std::cout << " p<enter> previous file" << std::endl;
+ std::cout << " <digit><enter> seek (0% - 90%)" << std::endl;
+ std::cout << " q<enter> quit" << std::endl << std::endl;
+
+ if (paint_) {
+ std::cout << " duration <none>" << std::endl;
+ std::cout << " title <none>" << std::endl;
+ std::cout << " artist <none>" << std::endl;
+ std::cout << " album <none>" << std::endl;
+ std::cout << " publisher <none>" << std::endl;
+ std::cout << " genre <none>" << std::endl;
+ std::cout << " composer <none>" << std::endl << std::endl;
+ std::cout << std::endl << std::endl << kUp << std::flush;
+ } else {
+ std::cout << std::endl;
+ }
+
+ CreateNewMediaTest();
+ Poll();
+ }
+
+ bool ConfigureIncomingConnection(
+ mojo::ApplicationConnection* connection) override {
+ return true;
+ }
+
+ private:
+ static const char *kHome;
+ static const char *kClearLine;
+ static const char *kUp;
+ static constexpr double ns_per_second = 1000000000.0;
+
+ // Processes arguments.
+ void ProcessArgs(const std::vector<std::string>& args) {
+ for (size_t i = 1; i < args.size(); ++i) {
+ const std::string& arg = args[i];
+ if (arg == "--paint") {
+ paint_ = true;
+ } else if (arg == "--no-paint") {
+ paint_ = false;
+ } else {
+ input_file_names_.push_back(arg);
+ }
+ }
+
+ input_file_names_iter_ = input_file_names_.begin();
+ }
+
+ // Creates a new MediaTest object to play the file referenced by
+ // input_file_names_iter_.
+ void CreateNewMediaTest() {
+ MOJO_DCHECK(input_file_names_iter_ != input_file_names_.end());
+ media_test_ = MediaTest::Create(app_, *input_file_names_iter_);
+
+ metadata_shown_ = false;
+ media_test_->RegisterUpdateCallback([this]() {
+ HandleMediaTestUpdateCallback();
+ });
+
+ media_test_->Play();
+ }
+
+ void HandleMediaTestUpdateCallback() {
+ if (media_test_->state() == MediaState::ENDED) {
+ // MediaTest doesn't appreciate being deleted in this callback.
+ // Next time Poll runs, we move on to the next file.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&MediaTestApp::PlayNext, base::Unretained(this)));
+ }
+
+ const MediaMetadataPtr& metadata = media_test_->metadata();
+
+ if (metadata) {
+ duration_ns_ = metadata->duration;
+ }
+
+ if (paint_) {
+ // Move the cursor up the terminal so we paint over the old metadata
+ // (7 lines) a blank line and the state line (total of 9 lines).
+ std::cout << kHome
+ << kUp << kUp << kUp << kUp << kUp << kUp << kUp << kUp << kUp;
+ }
+
+ if (!paint_ && metadata_shown_) {
+ // Do nothing.
+ } else if (metadata) {
+ metadata_shown_ = true;
+ std::cout << " duration " << std::setprecision(1) <<
+ double(metadata->duration) / ns_per_second << " seconds"
+ << clear_line() << std::endl;
+ std::cout << " title " <<
+ (metadata->title ? metadata->title : "<none>")
+ << clear_line() << std::endl;
+ std::cout << " artist " <<
+ (metadata->artist ? metadata->artist : "<none>")
+ << clear_line() << std::endl;
+ std::cout << " album " <<
+ (metadata->album ? metadata->album : "<none>")
+ << clear_line() << std::endl;
+ std::cout << " publisher " <<
+ (metadata->publisher ? metadata->publisher : "<none>")
+ << clear_line() << std::endl;
+ std::cout << " genre " <<
+ (metadata->genre ? metadata->genre : "<none>")
+ << clear_line() << std::endl;
+ std::cout << " composer " <<
+ (metadata->composer ? metadata->composer : "<none>")
+ << clear_line() << std::endl << std::endl;
+ } else {
+ std::cout << " duration <none>" << kClearLine << std::endl;
+ std::cout << " title <none>" << kClearLine << std::endl;
+ std::cout << " artist <none>" << kClearLine << std::endl;
+ std::cout << " album <none>" << kClearLine << std::endl;
+ std::cout << " publisher <none>" << kClearLine << std::endl;
+ std::cout << " genre <none>" << kClearLine << std::endl;
+ std::cout << " composer <none>" << kClearLine << std::endl;
+ std::cout << std::endl;
+ }
+ std::cout << " " << state_string() << clear_line() << std::endl;
+ }
+
+ // Returns a string describing the MediaTest object's state.
+ const char* state_string() const {
+ switch (media_test_->state()) {
+ case MediaState::FAULT:
+ return "FAULT";
+ case MediaState::UNPREPARED:
+ return "unprepared";
+ case MediaState::PAUSED:
+ return "paused";
+ case MediaState::PLAYING:
+ return "playing";
+ case MediaState::ENDED:
+ return "ended";
+ }
+ return "UNSUPPORTED STATE VALUE";
+ }
+
+ // Handles a keystroke.
+ void HandleKeystroke(char keystroke) {
+ switch (keystroke) {
+ case '\n':
+ TogglePlayPause();
+ break;
+ case 'q':
+ base::MessageLoop::current()->Quit();
+ quit_ = true;
+ if (paint_) {
+ std::cout << kHome << kUp << " quitting" << kClearLine << std::endl
+ << kClearLine << std::endl;
+ } else {
+ std::cout << " quitting" << std::endl;
+ }
+ break;
+ case 'n':
+ if (++input_file_names_iter_ == input_file_names_.end()) {
+ input_file_names_iter_ = input_file_names_.begin();
+ }
+ CreateNewMediaTest();
+ break;
+ case 'p':
+ if (input_file_names_iter_ == input_file_names_.begin()) {
+ input_file_names_iter_ = input_file_names_.end();
+ }
+ input_file_names_iter_--;
+ CreateNewMediaTest();
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': {
+ int64_t position_ns = ((keystroke - '0') / 10.0) * duration_ns_;
+ media_test_->Seek(position_ns);
+ if (!paint_) {
+ std::cout << " seeking to " << std::fixed << std::setprecision(1)
+ << double(position_ns) / ns_per_second
+ << " seconds " << std::endl;
+ }
+ break;
+ }
+ }
+ }
+
+ // Toggles between play and pause (prepared) states.
+ void TogglePlayPause() {
+ switch (media_test_->state()) {
+ case MediaState::PAUSED:
+ media_test_->Play();
+ break;
+ case MediaState::PLAYING:
+ media_test_->Pause();
+ break;
+ case MediaState::ENDED:
+ if (input_file_names_.size() == 1) {
+ // Replaying the only file. Reuse the same MediaTest instance.
+ media_test_->Seek(0);
+ media_test_->Play();
+ } else {
+ // Starting a new file. Create a new MediaTest instance.
+ CreateNewMediaTest();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Does any needed work and schedules itself to run again soon. Quits when
+ // quit_ is true.
+ void Poll() {
+ MOJO_DCHECK(!quit_);
+
+ char keystroke = Keystroke();
+ if (keystroke != 0) {
+ HandleKeystroke(keystroke);
+ }
+
+ if (quit_) {
+ // Eat the any additional keystrokes, which would otherwise make it to the
+ // command shell.
+ while (Keystroke() != 0) {
+ // Do nothing.
+ }
+ return;
+ }
+
+ if (paint_) {
+ std::cout << kHome << " " << std::fixed << std::setprecision(1)
+ << double(media_test_->position_ns()) / ns_per_second
+ << " seconds " << kClearLine << std::flush;
+ }
+
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&MediaTestApp::Poll, base::Unretained(this)),
+ base::TimeDelta::FromMilliseconds(100));
+ }
+
+ void PlayNext() {
+ if (++input_file_names_iter_ == input_file_names_.end()) {
+ input_file_names_iter_ = input_file_names_.begin();
+ } else {
+ CreateNewMediaTest();
+ }
+ }
+
+ const char* clear_line() const {
+ return paint_ ? kClearLine : "";
+ }
+
+ mojo::ApplicationImpl* app_;
+ std::unique_ptr<MediaTest> media_test_;
+ std::deque<std::string> input_file_names_;
+ decltype(input_file_names_.begin()) input_file_names_iter_;
+ bool quit_ = false;
+ bool paint_ = true;
+ bool metadata_shown_ = false;
+ uint64_t duration_ns_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaTestApp);
+};
+
+const char* MediaTestApp::kHome = "\r";
+const char* MediaTestApp::kClearLine = "\033[K";
+const char* MediaTestApp::kUp = "\033[A";
+
+} // namespace examples
+} // namespace media
+} // namespace mojo
+
+MojoResult MojoMain(MojoHandle application_request) {
+ mojo::ApplicationRunnerChromium
+ runner(new mojo::media::examples::MediaTestApp);
+ return runner.Run(application_request);
+}

Powered by Google App Engine
This is Rietveld 408576698