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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 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
5 #include <deque>
6 #include <iomanip>
7 #include <iostream>
8
9 #include "base/bind.h"
10 #include "examples/media_test/keystroke.h"
11 #include "examples/media_test/media_test.h"
12 #include "mojo/application/application_runner_chromium.h"
13 #include "mojo/public/c/system/main.h"
14 #include "mojo/public/cpp/application/application_connection.h"
15 #include "mojo/public/cpp/application/application_delegate.h"
16 #include "mojo/public/cpp/application/application_impl.h"
17
18 namespace mojo {
19 namespace media {
20 namespace examples {
21
22 class MediaTestApp : public mojo::ApplicationDelegate {
23 public:
24 MediaTestApp() {}
25
26 ~MediaTestApp() override {}
27
28 // ApplicationDelegate implementation.
29 void Initialize(mojo::ApplicationImpl* app) override {
30 app_ = app;
31 ProcessArgs(app->args());
32
33 std::cout << std::endl << "MEDIA TEST" << std::endl << std::endl;
34
35 if (input_file_names_.empty()) {
36 std::cout << "Please provide the names of the files you want to play;"
37 << " for example:" << std::endl;
38 std::cout << "mojo/devtools/common/mojo_run \\" << std::endl;
39 std::cout << " \"https://core.mojoapps.io/media_test.mojo \\"
40 << std::endl;
41 std::cout << " file:///usr/local/google/home/you/superstition.ogg \\"
42 << std::endl;
43 std::cout << " file:///usr/local/google/home/you/higherground.ogg\""
44 << std::endl << std::endl;
45 base::MessageLoop::current()->Quit();
46 return;
47 }
48
49 std::cout << " <enter> play/pause" << std::endl;
50 std::cout << " n<enter> next file" << std::endl;
51 std::cout << " p<enter> previous file" << std::endl;
52 std::cout << " <digit><enter> seek (0% - 90%)" << std::endl;
53 std::cout << " q<enter> quit" << std::endl << std::endl;
54
55 if (paint_) {
56 std::cout << " duration <none>" << std::endl;
57 std::cout << " title <none>" << std::endl;
58 std::cout << " artist <none>" << std::endl;
59 std::cout << " album <none>" << std::endl;
60 std::cout << " publisher <none>" << std::endl;
61 std::cout << " genre <none>" << std::endl;
62 std::cout << " composer <none>" << std::endl << std::endl;
63 std::cout << std::endl << std::endl << kUp << std::flush;
64 } else {
65 std::cout << std::endl;
66 }
67
68 CreateNewMediaTest();
69 Poll();
70 }
71
72 bool ConfigureIncomingConnection(
73 mojo::ApplicationConnection* connection) override {
74 return true;
75 }
76
77 private:
78 static const char *kHome;
79 static const char *kClearLine;
80 static const char *kUp;
81 static constexpr double ns_per_second = 1000000000.0;
82
83 // Processes arguments.
84 void ProcessArgs(const std::vector<std::string>& args) {
85 for (size_t i = 1; i < args.size(); ++i) {
86 const std::string& arg = args[i];
87 if (arg == "--paint") {
88 paint_ = true;
89 } else if (arg == "--no-paint") {
90 paint_ = false;
91 } else {
92 input_file_names_.push_back(arg);
93 }
94 }
95
96 input_file_names_iter_ = input_file_names_.begin();
97 }
98
99 // Creates a new MediaTest object to play the file referenced by
100 // input_file_names_iter_.
101 void CreateNewMediaTest() {
102 MOJO_DCHECK(input_file_names_iter_ != input_file_names_.end());
103 media_test_ = MediaTest::Create(app_, *input_file_names_iter_);
104
105 metadata_shown_ = false;
106 media_test_->RegisterUpdateCallback([this]() {
107 HandleMediaTestUpdateCallback();
108 });
109
110 media_test_->Play();
111 }
112
113 void HandleMediaTestUpdateCallback() {
114 if (media_test_->state() == MediaState::ENDED) {
115 // MediaTest doesn't appreciate being deleted in this callback.
116 // Next time Poll runs, we move on to the next file.
117 base::MessageLoop::current()->PostTask(
118 FROM_HERE,
119 base::Bind(&MediaTestApp::PlayNext, base::Unretained(this)));
120 }
121
122 const MediaMetadataPtr& metadata = media_test_->metadata();
123
124 if (metadata) {
125 duration_ns_ = metadata->duration;
126 }
127
128 if (paint_) {
129 // Move the cursor up the terminal so we paint over the old metadata
130 // (7 lines) a blank line and the state line (total of 9 lines).
131 std::cout << kHome
132 << kUp << kUp << kUp << kUp << kUp << kUp << kUp << kUp << kUp;
133 }
134
135 if (!paint_ && metadata_shown_) {
136 // Do nothing.
137 } else if (metadata) {
138 metadata_shown_ = true;
139 std::cout << " duration " << std::setprecision(1) <<
140 double(metadata->duration) / ns_per_second << " seconds"
141 << clear_line() << std::endl;
142 std::cout << " title " <<
143 (metadata->title ? metadata->title : "<none>")
144 << clear_line() << std::endl;
145 std::cout << " artist " <<
146 (metadata->artist ? metadata->artist : "<none>")
147 << clear_line() << std::endl;
148 std::cout << " album " <<
149 (metadata->album ? metadata->album : "<none>")
150 << clear_line() << std::endl;
151 std::cout << " publisher " <<
152 (metadata->publisher ? metadata->publisher : "<none>")
153 << clear_line() << std::endl;
154 std::cout << " genre " <<
155 (metadata->genre ? metadata->genre : "<none>")
156 << clear_line() << std::endl;
157 std::cout << " composer " <<
158 (metadata->composer ? metadata->composer : "<none>")
159 << clear_line() << std::endl << std::endl;
160 } else {
161 std::cout << " duration <none>" << kClearLine << std::endl;
162 std::cout << " title <none>" << kClearLine << std::endl;
163 std::cout << " artist <none>" << kClearLine << std::endl;
164 std::cout << " album <none>" << kClearLine << std::endl;
165 std::cout << " publisher <none>" << kClearLine << std::endl;
166 std::cout << " genre <none>" << kClearLine << std::endl;
167 std::cout << " composer <none>" << kClearLine << std::endl;
168 std::cout << std::endl;
169 }
170 std::cout << " " << state_string() << clear_line() << std::endl;
171 }
172
173 // Returns a string describing the MediaTest object's state.
174 const char* state_string() const {
175 switch (media_test_->state()) {
176 case MediaState::FAULT:
177 return "FAULT";
178 case MediaState::UNPREPARED:
179 return "unprepared";
180 case MediaState::PAUSED:
181 return "paused";
182 case MediaState::PLAYING:
183 return "playing";
184 case MediaState::ENDED:
185 return "ended";
186 }
187 return "UNSUPPORTED STATE VALUE";
188 }
189
190 // Handles a keystroke.
191 void HandleKeystroke(char keystroke) {
192 switch (keystroke) {
193 case '\n':
194 TogglePlayPause();
195 break;
196 case 'q':
197 base::MessageLoop::current()->Quit();
198 quit_ = true;
199 if (paint_) {
200 std::cout << kHome << kUp << " quitting" << kClearLine << std::endl
201 << kClearLine << std::endl;
202 } else {
203 std::cout << " quitting" << std::endl;
204 }
205 break;
206 case 'n':
207 if (++input_file_names_iter_ == input_file_names_.end()) {
208 input_file_names_iter_ = input_file_names_.begin();
209 }
210 CreateNewMediaTest();
211 break;
212 case 'p':
213 if (input_file_names_iter_ == input_file_names_.begin()) {
214 input_file_names_iter_ = input_file_names_.end();
215 }
216 input_file_names_iter_--;
217 CreateNewMediaTest();
218 break;
219 case '0':
220 case '1':
221 case '2':
222 case '3':
223 case '4':
224 case '5':
225 case '6':
226 case '7':
227 case '8':
228 case '9': {
229 int64_t position_ns = ((keystroke - '0') / 10.0) * duration_ns_;
230 media_test_->Seek(position_ns);
231 if (!paint_) {
232 std::cout << " seeking to " << std::fixed << std::setprecision(1)
233 << double(position_ns) / ns_per_second
234 << " seconds " << std::endl;
235 }
236 break;
237 }
238 }
239 }
240
241 // Toggles between play and pause (prepared) states.
242 void TogglePlayPause() {
243 switch (media_test_->state()) {
244 case MediaState::PAUSED:
245 media_test_->Play();
246 break;
247 case MediaState::PLAYING:
248 media_test_->Pause();
249 break;
250 case MediaState::ENDED:
251 if (input_file_names_.size() == 1) {
252 // Replaying the only file. Reuse the same MediaTest instance.
253 media_test_->Seek(0);
254 media_test_->Play();
255 } else {
256 // Starting a new file. Create a new MediaTest instance.
257 CreateNewMediaTest();
258 }
259 break;
260 default:
261 break;
262 }
263 }
264
265 // Does any needed work and schedules itself to run again soon. Quits when
266 // quit_ is true.
267 void Poll() {
268 MOJO_DCHECK(!quit_);
269
270 char keystroke = Keystroke();
271 if (keystroke != 0) {
272 HandleKeystroke(keystroke);
273 }
274
275 if (quit_) {
276 // Eat the any additional keystrokes, which would otherwise make it to the
277 // command shell.
278 while (Keystroke() != 0) {
279 // Do nothing.
280 }
281 return;
282 }
283
284 if (paint_) {
285 std::cout << kHome << " " << std::fixed << std::setprecision(1)
286 << double(media_test_->position_ns()) / ns_per_second
287 << " seconds " << kClearLine << std::flush;
288 }
289
290 base::MessageLoop::current()->PostDelayedTask(
291 FROM_HERE,
292 base::Bind(&MediaTestApp::Poll, base::Unretained(this)),
293 base::TimeDelta::FromMilliseconds(100));
294 }
295
296 void PlayNext() {
297 if (++input_file_names_iter_ == input_file_names_.end()) {
298 input_file_names_iter_ = input_file_names_.begin();
299 } else {
300 CreateNewMediaTest();
301 }
302 }
303
304 const char* clear_line() const {
305 return paint_ ? kClearLine : "";
306 }
307
308 mojo::ApplicationImpl* app_;
309 std::unique_ptr<MediaTest> media_test_;
310 std::deque<std::string> input_file_names_;
311 decltype(input_file_names_.begin()) input_file_names_iter_;
312 bool quit_ = false;
313 bool paint_ = true;
314 bool metadata_shown_ = false;
315 uint64_t duration_ns_;
316
317 DISALLOW_COPY_AND_ASSIGN(MediaTestApp);
318 };
319
320 const char* MediaTestApp::kHome = "\r";
321 const char* MediaTestApp::kClearLine = "\033[K";
322 const char* MediaTestApp::kUp = "\033[A";
323
324 } // namespace examples
325 } // namespace media
326 } // namespace mojo
327
328 MojoResult MojoMain(MojoHandle application_request) {
329 mojo::ApplicationRunnerChromium
330 runner(new mojo::media::examples::MediaTestApp);
331 return runner.Run(application_request);
332 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698