OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <iostream> | 5 #include <iostream> |
6 #include <signal.h> | 6 #include <signal.h> |
7 #include <X11/keysym.h> | 7 #include <X11/keysym.h> |
8 #include <X11/Xlib.h> | 8 #include <X11/Xlib.h> |
9 | 9 |
10 #include "base/at_exit.h" | 10 #include "base/at_exit.h" |
11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
12 #include "base/file_path.h" | 12 #include "base/file_path.h" |
13 #include "base/scoped_ptr.h" | 13 #include "base/scoped_ptr.h" |
14 #include "base/thread.h" | 14 #include "base/thread.h" |
15 #include "base/waitable_event.h" | 15 #include "media/base/callback.h" |
16 #include "media/base/media.h" | 16 #include "media/base/media.h" |
17 #include "media/base/media_switches.h" | 17 #include "media/base/media_switches.h" |
18 #include "media/base/pipeline_impl.h" | 18 #include "media/base/pipeline_impl.h" |
19 #include "media/filters/audio_renderer_impl.h" | 19 #include "media/filters/audio_renderer_impl.h" |
20 #include "media/filters/ffmpeg_audio_decoder.h" | 20 #include "media/filters/ffmpeg_audio_decoder.h" |
21 #include "media/filters/ffmpeg_demuxer.h" | 21 #include "media/filters/ffmpeg_demuxer.h" |
22 #include "media/filters/ffmpeg_video_decoder.h" | 22 #include "media/filters/ffmpeg_video_decoder.h" |
23 #include "media/filters/file_data_source.h" | 23 #include "media/filters/file_data_source.h" |
24 #include "media/filters/null_audio_renderer.h" | 24 #include "media/filters/null_audio_renderer.h" |
25 #include "media/filters/omx_video_decoder.h" | 25 #include "media/filters/omx_video_decoder.h" |
26 | 26 |
27 #if defined(RENDERER_GL) | 27 #if defined(RENDERER_GL) |
28 #include "media/tools/player_x11/gl_video_renderer.h" | 28 #include "media/tools/player_x11/gl_video_renderer.h" |
29 typedef GlVideoRenderer Renderer; | 29 typedef GlVideoRenderer Renderer; |
30 #elif defined(RENDERER_GLES) | 30 #elif defined(RENDERER_GLES) |
31 #include "media/tools/player_x11/gles_video_renderer.h" | 31 #include "media/tools/player_x11/gles_video_renderer.h" |
32 typedef GlesVideoRenderer Renderer; | 32 typedef GlesVideoRenderer Renderer; |
33 #elif defined(RENDERER_X11) | 33 #elif defined(RENDERER_X11) |
34 #include "media/tools/player_x11/x11_video_renderer.h" | 34 #include "media/tools/player_x11/x11_video_renderer.h" |
35 typedef X11VideoRenderer Renderer; | 35 typedef X11VideoRenderer Renderer; |
36 #else | 36 #else |
37 #error No video renderer defined. | 37 #error No video renderer defined. |
38 #endif | 38 #endif |
39 | 39 |
40 Display* g_display = NULL; | 40 Display* g_display = NULL; |
41 Window g_window = 0; | 41 Window g_window = 0; |
42 bool g_running = false; | 42 bool g_running = false; |
43 | 43 |
| 44 void Quit(MessageLoop* message_loop) { |
| 45 message_loop->PostTask(FROM_HERE, new MessageLoop::QuitTask()); |
| 46 } |
| 47 |
44 // Initialize X11. Returns true if successful. This method creates the X11 | 48 // Initialize X11. Returns true if successful. This method creates the X11 |
45 // window. Further initialization is done in X11VideoRenderer. | 49 // window. Further initialization is done in X11VideoRenderer. |
46 bool InitX11() { | 50 bool InitX11() { |
47 g_display = XOpenDisplay(NULL); | 51 g_display = XOpenDisplay(NULL); |
48 if (!g_display) { | 52 if (!g_display) { |
49 std::cout << "Error - cannot open display" << std::endl; | 53 std::cout << "Error - cannot open display" << std::endl; |
50 return false; | 54 return false; |
51 } | 55 } |
52 | 56 |
53 // Get properties of the screen. | 57 // Get properties of the screen. |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 return true; | 128 return true; |
125 } | 129 } |
126 | 130 |
127 void TerminateHandler(int signal) { | 131 void TerminateHandler(int signal) { |
128 g_running = false; | 132 g_running = false; |
129 } | 133 } |
130 | 134 |
131 void PeriodicalUpdate( | 135 void PeriodicalUpdate( |
132 media::PipelineImpl* pipeline, | 136 media::PipelineImpl* pipeline, |
133 MessageLoop* message_loop, | 137 MessageLoop* message_loop, |
134 base::WaitableEvent* stop_event, | |
135 bool audio_only) { | 138 bool audio_only) { |
136 if (!g_running) { | 139 if (!g_running) { |
137 message_loop->Quit(); | 140 message_loop->Quit(); |
138 return; | 141 return; |
139 } | 142 } |
140 | 143 |
141 // Consume all the X events | 144 // Consume all the X events |
142 while (XPending(g_display)) { | 145 while (XPending(g_display)) { |
143 XEvent e; | 146 XEvent e; |
144 XNextEvent(g_display, &e); | 147 XNextEvent(g_display, &e); |
(...skipping 21 matching lines...) Expand all Loading... |
166 &depth); | 169 &depth); |
167 base::TimeDelta time = pipeline->GetMediaDuration(); | 170 base::TimeDelta time = pipeline->GetMediaDuration(); |
168 pipeline->Seek(time*e.xbutton.x/width, NULL); | 171 pipeline->Seek(time*e.xbutton.x/width, NULL); |
169 } | 172 } |
170 break; | 173 break; |
171 case KeyPress: | 174 case KeyPress: |
172 { | 175 { |
173 KeySym key = XKeycodeToKeysym(g_display, e.xkey.keycode, 0); | 176 KeySym key = XKeycodeToKeysym(g_display, e.xkey.keycode, 0); |
174 if (key == XK_Escape) { | 177 if (key == XK_Escape) { |
175 g_running = false; | 178 g_running = false; |
176 // QuitNow is more responsive than Quit since renderer_base is till | 179 // Quit message_loop only when pipeline is fully stopped. |
177 // posting paint messages. | 180 pipeline->Stop(media::TaskToCallbackAdapter::NewCallback( |
178 pipeline->Stop(NewCallback(stop_event, | 181 NewRunnableFunction(Quit, message_loop))); |
179 &base::WaitableEvent::Signal)); | |
180 message_loop->Quit(); | |
181 return; | 182 return; |
182 } else if (key == XK_space) { | 183 } else if (key == XK_space) { |
183 if (pipeline->GetPlaybackRate() < 0.01f) // paused | 184 if (pipeline->GetPlaybackRate() < 0.01f) // paused |
184 pipeline->SetPlaybackRate(1.0f); | 185 pipeline->SetPlaybackRate(1.0f); |
185 else | 186 else |
186 pipeline->SetPlaybackRate(0.0f); | 187 pipeline->SetPlaybackRate(0.0f); |
187 } | 188 } |
188 } | 189 } |
189 break; | 190 break; |
190 default: | 191 default: |
191 break; | 192 break; |
192 } | 193 } |
193 } | 194 } |
194 | 195 |
195 message_loop->PostDelayedTask(FROM_HERE, | 196 message_loop->PostDelayedTask(FROM_HERE, |
196 NewRunnableFunction(PeriodicalUpdate, pipeline, | 197 NewRunnableFunction(PeriodicalUpdate, pipeline, |
197 message_loop, stop_event, audio_only), 10); | 198 message_loop, audio_only), 10); |
198 } | 199 } |
199 | 200 |
200 int main(int argc, char** argv) { | 201 int main(int argc, char** argv) { |
201 // Read arguments. | 202 // Read arguments. |
202 if (argc == 1) { | 203 if (argc == 1) { |
203 std::cout << "Usage: " << argv[0] << " --file=FILE" << std::endl | 204 std::cout << "Usage: " << argv[0] << " --file=FILE" << std::endl |
204 << std::endl | 205 << std::endl |
205 << "Optional arguments:" << std::endl | 206 << "Optional arguments:" << std::endl |
206 << " [--enable-openmax]" | 207 << " [--enable-openmax]" |
207 << " [--audio]" | 208 << " [--audio]" |
(...skipping 17 matching lines...) Expand all Loading... |
225 | 226 |
226 // Initialize X11. | 227 // Initialize X11. |
227 if (!InitX11()) | 228 if (!InitX11()) |
228 return 1; | 229 return 1; |
229 | 230 |
230 // Initialize the pipeline thread and the pipeline. | 231 // Initialize the pipeline thread and the pipeline. |
231 base::AtExitManager at_exit; | 232 base::AtExitManager at_exit; |
232 scoped_ptr<base::Thread> thread; | 233 scoped_ptr<base::Thread> thread; |
233 scoped_refptr<media::PipelineImpl> pipeline; | 234 scoped_refptr<media::PipelineImpl> pipeline; |
234 MessageLoop message_loop; | 235 MessageLoop message_loop; |
235 base::WaitableEvent stop_event(false, false); | |
236 thread.reset(new base::Thread("PipelineThread")); | 236 thread.reset(new base::Thread("PipelineThread")); |
237 thread->Start(); | 237 thread->Start(); |
238 if (InitPipeline(thread->message_loop(), filename.c_str(), | 238 if (InitPipeline(thread->message_loop(), filename.c_str(), |
239 enable_audio, &pipeline, &message_loop)) { | 239 enable_audio, &pipeline, &message_loop)) { |
240 // Main loop of the application. | 240 // Main loop of the application. |
241 g_running = true; | 241 g_running = true; |
242 | 242 |
243 // Check if video is present. | 243 // Check if video is present. |
244 audio_only = !pipeline->IsRendered(media::mime_type::kMajorTypeVideo); | 244 audio_only = !pipeline->IsRendered(media::mime_type::kMajorTypeVideo); |
245 | 245 |
246 message_loop.PostTask(FROM_HERE, | 246 message_loop.PostTask(FROM_HERE, |
247 NewRunnableFunction(PeriodicalUpdate, pipeline.get(), | 247 NewRunnableFunction(PeriodicalUpdate, pipeline.get(), |
248 &message_loop, &stop_event, audio_only)); | 248 &message_loop, audio_only)); |
249 message_loop.Run(); | 249 message_loop.Run(); |
250 | |
251 // Need to wait for pipeline to be fully stopped before stopping the thread. | |
252 stop_event.Wait(); | |
253 } else{ | 250 } else{ |
254 std::cout << "Pipeline initialization failed..." << std::endl; | 251 std::cout << "Pipeline initialization failed..." << std::endl; |
255 } | 252 } |
256 | 253 |
257 // Cleanup tasks. | 254 // Cleanup tasks. |
258 thread->Stop(); | 255 thread->Stop(); |
259 XDestroyWindow(g_display, g_window); | 256 XDestroyWindow(g_display, g_window); |
260 XCloseDisplay(g_display); | 257 XCloseDisplay(g_display); |
261 return 0; | 258 return 0; |
262 } | 259 } |
OLD | NEW |