15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <signal.h>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <iostream>  // NOLINT
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/at_exit.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/scoped_vector.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/platform_thread.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/audio_manager.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/null_audio_sink.h"
19effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "media/base/audio_hardware_config.h"
205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "media/base/bind_to_current_loop.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/decryptor.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/media.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/media_log.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/media_switches.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/pipeline.h"
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "media/base/text_track.h"
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "media/base/text_track_config.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/video_frame.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/filters/audio_renderer_impl.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/filters/ffmpeg_audio_decoder.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/filters/ffmpeg_demuxer.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/filters/ffmpeg_video_decoder.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/filters/file_data_source.h"
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "media/filters/renderer_impl.h"
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "media/filters/video_renderer_impl.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/tools/player_x11/data_source_logger.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Include X11 headers here because X11/Xlib.h #define's Status
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// which causes compiler errors with Status enum declarations
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in media::DemuxerStream & media::AudioDecoder.
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <X11/XKBlib.h>
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <X11/Xlib.h>
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/tools/player_x11/gl_video_renderer.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/tools/player_x11/x11_video_renderer.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static Display* g_display = NULL;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static Window g_window = 0;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool g_running = false;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)media::AudioManager* g_audio_manager = NULL;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)scoped_ptr<media::DataSource> CreateDataSource(const std::string& file_path) {
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  media::FileDataSource* file_data_source = new media::FileDataSource();
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK(file_data_source->Initialize(base::FilePath(file_path)));
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<media::DataSource> data_source(file_data_source);
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return data_source.Pass();
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Initialize X11. Returns true if successful. This method creates the X11
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// window. Further initialization is done in X11VideoRenderer.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool InitX11() {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_display = XOpenDisplay(NULL);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_display) {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::cout << "Error - cannot open display" << std::endl;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get properties of the screen.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int screen = DefaultScreen(g_display);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int root_window = RootWindow(g_display, screen);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates the window.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_window = XCreateSimpleWindow(g_display, root_window, 1, 1, 100, 50, 0,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 BlackPixel(g_display, screen),
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 BlackPixel(g_display, screen));
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XStoreName(g_display, g_window, "X11 Media Player");
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XSelectInput(g_display, g_window,
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               ExposureMask | ButtonPressMask | KeyPressMask);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XMapWindow(g_display, g_window);
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
86effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstatic void DoNothing() {}
87effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
88effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstatic void OnStatus(media::PipelineStatus status) {}
89effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
90effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstatic void OnMetadata(media::PipelineMetadata metadata) {}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
92116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic void OnBufferingStateChanged(media::BufferingState buffering_state) {}
93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic void OnAddTextTrack(const media::TextTrackConfig& config,
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                           const media::AddTextTrackDoneCB& done_cb) {
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
98424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)static void NeedKey(const std::string& type,
99424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                    const std::vector<uint8>& init_data) {
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::cout << "File is encrypted." << std::endl;
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static void SaveStatusAndSignal(base::WaitableEvent* event,
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                media::PipelineStatus* status_out,
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                media::PipelineStatus status) {
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  *status_out = status;
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  event->Signal();
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(vrk): Re-enabled audio. (crbug.com/112159)
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InitPipeline(
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    media::Pipeline* pipeline,
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    media::Demuxer* demuxer,
1155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const media::VideoRendererImpl::PaintCB& paint_cb,
1165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    bool /* enable_audio */) {
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ScopedVector<media::VideoDecoder> video_decoders;
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  video_decoders.push_back(new media::FFmpegVideoDecoder(task_runner));
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<media::VideoRenderer> video_renderer(
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      new media::VideoRendererImpl(task_runner,
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   video_decoders.Pass(),
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   media::SetDecryptorReadyCB(),
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   paint_cb,
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   true,
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   new media::MediaLog()));
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScopedVector<media::AudioDecoder> audio_decoders;
128010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  audio_decoders.push_back(new media::FFmpegAudioDecoder(task_runner,
129010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                                         media::LogCB()));
130effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  media::AudioParameters out_params(
131effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
132effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      media::CHANNEL_LAYOUT_STEREO,
133effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      44100,
134effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      16,
135effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      512);
136effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  media::AudioHardwareConfig hardware_config(out_params, out_params);
137effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
138effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  scoped_ptr<media::AudioRenderer> audio_renderer(
139effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      new media::AudioRendererImpl(task_runner,
140effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                   new media::NullAudioSink(task_runner),
141effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                   audio_decoders.Pass(),
142effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                   media::SetDecryptorReadyCB(),
1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   hardware_config,
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   new media::MediaLog()));
145effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<media::Renderer> renderer(new media::RendererImpl(
1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      task_runner, demuxer, audio_renderer.Pass(), video_renderer.Pass()));
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::WaitableEvent event(true, false);
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  media::PipelineStatus status;
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  pipeline->Start(demuxer,
1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                  renderer.Pass(),
1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                  base::Bind(&DoNothing),
1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                  base::Bind(&OnStatus),
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                  base::Bind(&SaveStatusAndSignal, &event, &status),
1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                  base::Bind(&OnMetadata),
1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                  base::Bind(&OnBufferingStateChanged),
1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                  base::Bind(&DoNothing),
1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                  base::Bind(&OnAddTextTrack));
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Wait until the pipeline is fully initialized.
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  event.Wait();
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CHECK_EQ(status, media::PIPELINE_OK) << "Pipeline initialization failed";
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // And start the playback.
167b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  pipeline->SetPlaybackRate(1.0f);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TerminateHandler(int signal) {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_running = false;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PeriodicalUpdate(
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    media::Pipeline* pipeline,
176effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    base::MessageLoop* message_loop) {
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_running) {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // interrupt signal was received during last time period.
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Quit message_loop only when pipeline is fully stopped.
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    pipeline->Stop(base::MessageLoop::QuitClosure());
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Consume all the X events
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (XPending(g_display)) {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XEvent e;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XNextEvent(g_display, &e);
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (e.type) {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ButtonPress:
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          Window window;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          int x, y;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          unsigned int width, height, border_width, depth;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          XGetGeometry(g_display,
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       g_window,
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       &window,
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       &x,
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       &y,
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       &width,
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       &height,
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       &border_width,
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       &depth);
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::TimeDelta time = pipeline->GetMediaDuration();
204effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          pipeline->Seek(time*e.xbutton.x/width, base::Bind(&OnStatus));
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case KeyPress:
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          KeySym key = XkbKeycodeToKeysym(g_display, e.xkey.keycode, 0, 0);
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (key == XK_Escape) {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            g_running = false;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // Quit message_loop only when pipeline is fully stopped.
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            pipeline->Stop(base::MessageLoop::QuitClosure());
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          } else if (key == XK_space) {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (pipeline->GetPlaybackRate() < 0.01f)  // paused
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              pipeline->SetPlaybackRate(1.0f);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            else
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              pipeline->SetPlaybackRate(0.0f);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_loop->PostDelayedTask(
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&PeriodicalUpdate,
231b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                 base::Unretained(pipeline),
232effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 message_loop),
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(10));
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int main(int argc, char** argv) {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AtExitManager at_exit;
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  media::InitializeMediaLibraryForTesting();
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine::Init(argc, argv);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine* command_line = CommandLine::ForCurrentProcess();
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string filename = command_line->GetSwitchValueASCII("file");
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (filename.empty()) {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::cout << "Usage: " << argv[0] << " --file=FILE" << std::endl
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << std::endl
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << "Optional arguments:" << std::endl
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << "  [--audio]"
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << "  [--alsa-device=DEVICE]"
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << "  [--use-gl]"
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << "  [--streaming]" << std::endl
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << " Press [ESC] to stop" << std::endl
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << " Press [SPACE] to toggle pause/play" << std::endl
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << " Press mouse left button to seek" << std::endl;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
258a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<media::AudioManager> audio_manager(
259a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      media::AudioManager::CreateForTesting());
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_audio_manager = audio_manager.get();
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
262eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  logging::LoggingSettings settings;
263eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
264eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  logging::InitLogging(settings);
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Install the signal handler.
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signal(SIGTERM, &TerminateHandler);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signal(SIGINT, &TerminateHandler);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Initialize X11.
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!InitX11())
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Initialize the pipeline thread and the pipeline.
275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::MessageLoop message_loop;
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::Thread media_thread("MediaThread");
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  media_thread.Start();
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  media::VideoRendererImpl::PaintCB paint_cb;
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (command_line->HasSwitch("use-gl")) {
2815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    paint_cb = media::BindToCurrentLoop(base::Bind(
2825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        &GlVideoRenderer::Paint, new GlVideoRenderer(g_display, g_window)));
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    paint_cb = media::BindToCurrentLoop(base::Bind(
2855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        &X11VideoRenderer::Paint, new X11VideoRenderer(g_display, g_window)));
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<media::DataSource> data_source(new DataSourceLogger(
289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      CreateDataSource(filename), command_line->HasSwitch("streaming")));
290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<media::Demuxer> demuxer(new media::FFmpegDemuxer(
291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      media_thread.message_loop_proxy(), data_source.get(),
292a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      base::Bind(&NeedKey), new media::MediaLog()));
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
294b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  media::Pipeline pipeline(media_thread.message_loop_proxy(),
295b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                           new media::MediaLog());
296b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  InitPipeline(&pipeline, media_thread.message_loop_proxy(), demuxer.get(),
2975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu               paint_cb, command_line->HasSwitch("audio"));
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Main loop of the application.
300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  g_running = true;
301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  message_loop.PostTask(FROM_HERE, base::Bind(
303effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      &PeriodicalUpdate, base::Unretained(&pipeline), &message_loop));
304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  message_loop.Run();
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cleanup tasks.
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  media_thread.Stop();
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Release callback which releases video renderer. Do this before cleaning up
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // X below since the video renderer has some X cleanup duties as well.
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  paint_cb.Reset();
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XDestroyWindow(g_display, g_window);
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XCloseDisplay(g_display);
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_audio_manager = NULL;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
319