From: Piotr Tworek Date: Tue, 3 Mar 2015 06:19:04 +0000 (+0900) Subject: Migrate multimedia support code to new chromium_impl structure. X-Git-Tag: submit/tizen/20190801.160004~1768 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=bb4ed5304b5274739808b488dd296ebfb6282f88;p=platform%2Fframework%2Fweb%2Fchromium-efl.git Migrate multimedia support code to new chromium_impl structure. The code implements internal chromium interfaces so it belongs in chromium part of new project structure. The expectation is it'll be possible to use it from both xwalk/content_shell and EWK. Due to the fact that xwalk gyp files (xwalk/build/xwalk_filename_rules.gypi) exclude files with tizen in their path from build if tizen gyp variable is set to 0 the code had to be renamed. These files were renamed to have the "efl" suffix instead, given that there were no Tizen specific (desktop build also builds them). This way we still keep the ability to build and test the code on desktop. Change-Id: Ic967fb97131152494520ac9232b986126918c969 Signed-off-by: Piotr Tworek Signed-off-by: Taeho Kim --- diff --git a/tizen_src/build/system.gyp b/tizen_src/build/system.gyp index 9d8689e4a51c..7279a7a8c347 100644 --- a/tizen_src/build/system.gyp +++ b/tizen_src/build/system.gyp @@ -216,5 +216,46 @@ }], ], }, # libtbm + { + 'target_name': 'gstreamer', + 'type': 'none', + 'conditions': [ + ['chromium_efl_tizen_version >= "2.4"', { + 'variables': { + 'dependent_pkgs': [ + 'gstreamer-1.0', + 'gstreamer-base-1.0', + 'gstreamer-app-1.0', + 'gstreamer-pbutils-1.0', + 'gstreamer-video-1.0', + ], + }, + }, { # for Tizen v2.X + 'variables': { + 'dependent_pkgs': [ + 'gstreamer-0.10', + 'gstreamer-base-0.10', + 'gstreamer-app-0.10', + 'gstreamer-pbutils-0.10', + 'gstreamer-interfaces-0.10', + 'gstreamer-video-0.10', + ], + }, + }] + ], + 'direct_dependent_settings': { + 'cflags': [ + '& demuxer, + int demuxer_client_id) + : demuxer_(demuxer), + demuxer_client_id_(demuxer_client_id) { } + + virtual ~Internal() { + DCHECK(ClientIDExists()) << demuxer_client_id_; + demuxer_->RemoveDemuxerClient(demuxer_client_id_); + } + + // media::DemuxerEfl implementation. + virtual void Initialize(media::DemuxerEflClient* client) override { + DCHECK(!ClientIDExists()) << demuxer_client_id_; + demuxer_->AddDemuxerClient(demuxer_client_id_, client); + } + + virtual void RequestDemuxerConfigs() override { + DCHECK(ClientIDExists()) << demuxer_client_id_; + demuxer_->Send(new MediaPlayerGstMsg_MediaConfigRequest( + demuxer_client_id_)); + } + + virtual void RequestDemuxerData(media::DemuxerStream::Type type) override { + DCHECK(ClientIDExists()) << demuxer_client_id_; + demuxer_->Send(new MediaPlayerGstMsg_ReadFromDemuxer( + demuxer_client_id_, type)); + } + + virtual void RequestDemuxerSeek( + const base::TimeDelta& time_to_seek) override { + DCHECK(ClientIDExists()) << demuxer_client_id_; + demuxer_->Send(new MediaPlayerGstMsg_DemuxerSeekRequest( + demuxer_client_id_, time_to_seek)); + } + + private: + // Helper for DCHECKing that the ID is still registered. + bool ClientIDExists() { + return demuxer_->demuxer_clients_.Lookup(demuxer_client_id_); + } + + scoped_refptr demuxer_; + int demuxer_client_id_; + + DISALLOW_COPY_AND_ASSIGN(Internal); +}; + +BrowserDemuxerEfl::BrowserDemuxerEfl() + : BrowserMessageFilter(MediaPlayerEflMsgStart) {} + +BrowserDemuxerEfl::~BrowserDemuxerEfl() {} + +void BrowserDemuxerEfl::OverrideThreadForMessage( + const IPC::Message& message, + BrowserThread::ID* thread) { + switch (message.type()) { + case MediaPlayerGstHostMsg_DemuxerReady::ID: + case MediaPlayerGstHostMsg_ReadFromDemuxerAck::ID: + case MediaPlayerGstHostMsg_BufferMetaDataAck::ID: + case MediaPlayerGstHostMsg_DurationChanged::ID: + case MediaPlayerGstHostMsg_DemuxerSeekDone::ID: + *thread = BrowserThread::UI; + return; + } +} + +bool BrowserDemuxerEfl::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(BrowserDemuxerEfl, message) + IPC_MESSAGE_HANDLER(MediaPlayerGstHostMsg_DemuxerReady, OnDemuxerReady) + IPC_MESSAGE_HANDLER(MediaPlayerGstHostMsg_ReadFromDemuxerAck, + OnReadFromDemuxerAck) + IPC_MESSAGE_HANDLER(MediaPlayerGstHostMsg_BufferMetaDataAck, + OnBufferMetaDataAck) + IPC_MESSAGE_HANDLER(MediaPlayerGstHostMsg_DurationChanged, + OnDurationChanged) + IPC_MESSAGE_HANDLER(MediaPlayerGstHostMsg_DemuxerSeekDone, + OnDemuxerSeekDone) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +scoped_ptr BrowserDemuxerEfl::CreateDemuxer( + int demuxer_client_id) { + return scoped_ptr( + new Internal(this, demuxer_client_id)); +} + +void BrowserDemuxerEfl::AddDemuxerClient( + int demuxer_client_id, + media::DemuxerEflClient* client) { + VLOG(1) << __FUNCTION__ << " peer_pid=" << peer_pid() + << " demuxer_client_id=" << demuxer_client_id; + demuxer_clients_.AddWithID(client, demuxer_client_id); +} + +void BrowserDemuxerEfl::RemoveDemuxerClient(int demuxer_client_id) { + VLOG(1) << __FUNCTION__ << " peer_pid=" << peer_pid() + << " demuxer_client_id=" << demuxer_client_id; + demuxer_clients_.Remove(demuxer_client_id); +} + +void BrowserDemuxerEfl::OnDemuxerReady( + int demuxer_client_id, + const media::DemuxerConfigs& configs) { + media::DemuxerEflClient* client = + demuxer_clients_.Lookup(demuxer_client_id); + if (client) + client->OnDemuxerConfigsAvailable(configs); +} + +void BrowserDemuxerEfl::OnReadFromDemuxerAck( + int demuxer_client_id, + base::SharedMemoryHandle foreign_memory_handle, + const media::DemuxedBufferMetaData& meta_data) { + media::DemuxerEflClient* client = + demuxer_clients_.Lookup(demuxer_client_id); + if (client) + client->OnDemuxerDataAvailable(foreign_memory_handle, meta_data); +} + +void BrowserDemuxerEfl::OnBufferMetaDataAck( + int demuxer_client_id, + const media::DemuxedBufferMetaData& meta_data) { + media::DemuxerEflClient* client = + demuxer_clients_.Lookup(demuxer_client_id); + if (client) + client->OnBufferMetaDataAvailable( meta_data); +} + +void BrowserDemuxerEfl::OnDemuxerSeekDone( + int demuxer_client_id, + const base::TimeDelta& actual_browser_seek_time) { + media::DemuxerEflClient* client = + demuxer_clients_.Lookup(demuxer_client_id); + if (client) + client->OnDemuxerSeekDone(actual_browser_seek_time); +} + +void BrowserDemuxerEfl::OnDurationChanged( + int demuxer_client_id, + const base::TimeDelta& duration) { + media::DemuxerEflClient* client = + demuxer_clients_.Lookup(demuxer_client_id); + if (client) + client->OnDemuxerDurationChanged(duration); +} + +} // namespace content diff --git a/tizen_src/chromium_impl/content/browser/media/efl/browser_demuxer_efl.h b/tizen_src/chromium_impl/content/browser/media/efl/browser_demuxer_efl.h new file mode 100644 index 000000000000..c6e60ff699d5 --- /dev/null +++ b/tizen_src/chromium_impl/content/browser/media/efl/browser_demuxer_efl.h @@ -0,0 +1,74 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_MEDIA_TIZEN_BROWSER_DEMUXER_EFL_H_ +#define CONTENT_BROWSER_MEDIA_TIZEN_BROWSER_DEMUXER_EFl_H_ + +#include "base/id_map.h" +#include "base/memory/shared_memory.h" +#include "content/public/browser/browser_message_filter.h" +#include "media/base/efl/demuxer_efl.h" + +namespace content { + +// Represents the browser process half of an IPC-based demuxer proxy. +// It vends out media::DemuxerEfl instances that are registered with an +// end point in the renderer process. +// +// Refer to RendererDemuxerEfl for the renderer process half. +class CONTENT_EXPORT BrowserDemuxerEfl : public BrowserMessageFilter { + public: + BrowserDemuxerEfl(); + + // BrowserMessageFilter overrides. + virtual void OverrideThreadForMessage( + const IPC::Message& message, + BrowserThread::ID* thread) override; + virtual bool OnMessageReceived(const IPC::Message& message) override; + + // Returns an uninitialized demuxer implementation associated with + // |demuxer_client_id|, which can be used to communicate with the real demuxer + // in the renderer process. + scoped_ptr CreateDemuxer(int demuxer_client_id); + + protected: + friend class base::RefCountedThreadSafe; + virtual ~BrowserDemuxerEfl(); + + private: + class Internal; + + // Called by internal demuxer implementations to add/remove a client + // association. + void AddDemuxerClient( + int demuxer_client_id, + media::DemuxerEflClient* client); + void RemoveDemuxerClient(int demuxer_client_id); + + // IPC message handlers. + void OnDemuxerReady( + int demuxer_client_id, + const media::DemuxerConfigs& configs); + void OnReadFromDemuxerAck( + int demuxer_client_id, + base::SharedMemoryHandle foreign_memory_handle, + const media::DemuxedBufferMetaData& meta_data); + void OnBufferMetaDataAck( + int demuxer_client_id, + const media::DemuxedBufferMetaData& meta_data); + void OnDemuxerSeekDone( + int demuxer_client_id, + const base::TimeDelta& actual_browser_seek_time); + void OnDurationChanged( + int demuxer_client_id, + const base::TimeDelta& duration); + + IDMap demuxer_clients_; + + DISALLOW_COPY_AND_ASSIGN(BrowserDemuxerEfl); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_MEDIA_TIZEN_BROWSER_DEMUXER_EFL_H_ diff --git a/tizen_src/chromium_impl/content/browser/media/efl/browser_media_player_manager_efl.cc b/tizen_src/chromium_impl/content/browser/media/efl/browser_media_player_manager_efl.cc new file mode 100644 index 000000000000..b178e3802102 --- /dev/null +++ b/tizen_src/chromium_impl/content/browser/media/efl/browser_media_player_manager_efl.cc @@ -0,0 +1,246 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/media/efl/browser_media_player_manager_efl.h" + +#include "base/memory/shared_memory.h" +#include "content/browser/media/efl/browser_demuxer_efl.h" +#include "content/browser/renderer_host/render_process_host_impl.h" +#include "content/common/media/efl/media_player_messages_efl.h" +#include "content/public/browser/web_contents.h" +#include "ipc/ipc_channel_proxy.h" +#include "ipc/ipc_logging.h" +#include "media/base/efl/media_source_player_gstreamer.h" + +#if defined(TIZEN_CAPI_PLAYER_SUPPORT) && defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +#include "media/base/tizen/media_player_bridge_capi.h" +#else +#include "media/base/efl/media_player_bridge_gstreamer.h" +#endif + +namespace content { + +BrowserMediaPlayerManagerEfl* BrowserMediaPlayerManagerEfl::Create( + RenderFrameHost* rfh) { + return new BrowserMediaPlayerManagerEfl(rfh); +} + +BrowserMediaPlayerManagerEfl::BrowserMediaPlayerManagerEfl( + RenderFrameHost* render_frame_host) + : render_frame_host_(render_frame_host), + web_contents_(WebContents::FromRenderFrameHost(render_frame_host)), + weak_ptr_factory_(this) { +} + +BrowserMediaPlayerManagerEfl::~BrowserMediaPlayerManagerEfl() { + for (ScopedVector::iterator it = players_.begin(); + it != players_.end(); ++it) { + (*it)->Destroy(); + } + players_.weak_clear(); +} + +media::MediaPlayerEfl* BrowserMediaPlayerManagerEfl::GetPlayer( + int player_id) { + for (ScopedVector::iterator it = players_.begin(); + it != players_.end(); ++it) { + if ((*it)->GetPlayerId() == player_id) + return *it; + } + return NULL; +} + +void BrowserMediaPlayerManagerEfl::OnNewFrameAvailable( + int player_id, + base::SharedMemoryHandle foreign_memory_handle, + uint32 length, base::TimeDelta timestamp) { + Send(new MediaPlayerGstMsg_NewFrameAvailable( + GetRoutingID(), player_id, foreign_memory_handle, length, timestamp)); +} + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +void BrowserMediaPlayerManagerEfl::OnPlatformSurfaceUpdated( + int player_id, + int pixmap_id, + base::TimeDelta timestamp) { + Send(new MediaPlayerGstMsg_PlatformSurfaceUpdated( + GetRoutingID(), player_id, pixmap_id, timestamp)); +} +#endif + +void BrowserMediaPlayerManagerEfl::OnTimeChanged(int player_id) { + Send(new MediaPlayerGstMsg_TimeChanged(GetRoutingID(), player_id)); +} + +void BrowserMediaPlayerManagerEfl::OnPauseStateChange( + int player_id, + bool state) { + Send(new MediaPlayerGstMsg_OnPauseStateChange( + GetRoutingID(), player_id, state)); +} + +void BrowserMediaPlayerManagerEfl::OnSeekStateChange( + int player_id, + bool state) { + Send(new MediaPlayerGstMsg_OnSeekStateChange( + GetRoutingID(), player_id, state)); +} + +void BrowserMediaPlayerManagerEfl::OnRequestSeek( + int player_id, + double seek_time) { + // To handle internal seek. + Send(new MediaPlayerGstMsg_SeekRequest( + GetRoutingID(), player_id, seek_time)); +} + +void BrowserMediaPlayerManagerEfl::OnTimeUpdate( + int player_id, + double current_time) { + Send(new MediaPlayerGstMsg_TimeUpdate( + GetRoutingID(), player_id, current_time)); +} + +void BrowserMediaPlayerManagerEfl::OnBufferUpdate( + int player_id, + std::vector buffer_range) { + Send(new MediaPlayerGstMsg_BufferUpdate( + GetRoutingID(), player_id, buffer_range)); +} + +void BrowserMediaPlayerManagerEfl::OnDurationChange( + int player_id, + double duration) { + Send(new MediaPlayerGstMsg_DurationChanged( + GetRoutingID(), player_id, duration)); +} + +void BrowserMediaPlayerManagerEfl::OnReadyStateChange( + int player_id, + media::MediaPlayerEfl::ReadyState state) { + Send(new MediaPlayerGstMsg_ReadyStateChange( + GetRoutingID(), player_id, state)); +} + +void BrowserMediaPlayerManagerEfl::OnNetworkStateChange( + int player_id, + media::MediaPlayerEfl::NetworkState state) { + Send(new MediaPlayerGstMsg_NetworkStateChange( + GetRoutingID(), player_id, state)); +} + +void BrowserMediaPlayerManagerEfl::OnMediaDataChange( + int player_id, + int format, + int height, + int width, + int media) { + Send(new MediaPlayerGstMsg_MediaDataChanged( + GetRoutingID(), player_id, format, height, width, media)); +} + +int BrowserMediaPlayerManagerEfl::GetRoutingID() { + if (!render_frame_host_) + return 0; + return render_frame_host_->GetRoutingID(); +} + +bool BrowserMediaPlayerManagerEfl::Send(IPC::Message* msg) { + if (!render_frame_host_) + return false; + return render_frame_host_->Send(msg); +} + +void BrowserMediaPlayerManagerEfl::OnInitialize( + int player_id, + MediaPlayerHostMsg_Initialize_Type type, + const GURL& url, + double volume, + int demuxer_client_id) { + RemovePlayer(player_id); + + if (type == MEDIA_PLAYER_TYPE_URL) { + +#if defined(TIZEN_CAPI_PLAYER_SUPPORT) && defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + LOG(INFO) << "MediaElement is using |CAPI| to play media"; + AddPlayer(new media::MediaPlayerBridgeCapi(player_id, url, volume, this)); +#else + LOG(INFO) << "MediaElement is using |Efl| to play media"; + AddPlayer( + new media::MediaPlayerBridgeGstreamer(player_id, url, volume, this)); +#endif + + } else if (type == MEDIA_PLAYER_TYPE_MEDIA_SOURCE) { + RenderProcessHostImpl* host = static_cast( + web_contents()->GetRenderProcessHost()); + AddPlayer(new media::MediaSourcePlayerGstreamer( + player_id, + host->browser_demuxer_efl()->CreateDemuxer(demuxer_client_id), + this)); + } else { + LOG(ERROR) << __FUNCTION__ << " Load type is wrong!"; + } +} + +void BrowserMediaPlayerManagerEfl::OnDestroy(int player_id) { + VLOG(1) << __FUNCTION__ << " " << player_id; + RemovePlayer(player_id); +} + +void BrowserMediaPlayerManagerEfl::OnPlay(int player_id) { + media::MediaPlayerEfl* player = GetPlayer(player_id); + if (player) + player->Play(); +} + +void BrowserMediaPlayerManagerEfl::OnPause(int player_id) { + media::MediaPlayerEfl* player = GetPlayer(player_id); + if (player) + player->Pause(false); +} + +void BrowserMediaPlayerManagerEfl::OnSetVolume( + int player_id, + double volume) { + media::MediaPlayerEfl* player = GetPlayer(player_id); + if (player) + player->SetVolume(volume); +} + +void BrowserMediaPlayerManagerEfl::OnSetRate(int player_id, double rate) { + media::MediaPlayerEfl* player = GetPlayer(player_id); + if (player) + player->SetRate(rate); +} + +void BrowserMediaPlayerManagerEfl::OnSeek(int player_id, double time) { + media::MediaPlayerEfl* player = GetPlayer(player_id); + if (player) + player->Seek(time); +} + +void BrowserMediaPlayerManagerEfl::AddPlayer( + media::MediaPlayerEfl* player) { + DCHECK(!GetPlayer(player->GetPlayerId())); + VLOG(1) << "BrowserMediaPlayerManagerEfl::" << __FUNCTION__ + << " Player-Id : " << player->GetPlayerId(); + players_.push_back(player); +} + +void BrowserMediaPlayerManagerEfl::RemovePlayer(int player_id) { + for (ScopedVector::iterator it = players_.begin(); + it != players_.end(); ++it) { + media::MediaPlayerEfl* player = *it; + if (player->GetPlayerId() == player_id) { + VLOG(1) << "BrowserMediaPlayerManagerEfl::" << __FUNCTION__ + << " Player-Id : " << player->GetPlayerId(); + players_.weak_erase(it); + player->Destroy(); + break; + } + } +} + +} // namespace content + diff --git a/tizen_src/chromium_impl/content/browser/media/efl/browser_media_player_manager_efl.h b/tizen_src/chromium_impl/content/browser/media/efl/browser_media_player_manager_efl.h new file mode 100644 index 000000000000..1178b699044e --- /dev/null +++ b/tizen_src/chromium_impl/content/browser/media/efl/browser_media_player_manager_efl.h @@ -0,0 +1,102 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_MEDIA_TIZEN_BROWSER_MEDIA_PLAYER_MANAGER_TIZEN_H_ +#define CONTENT_BROWSER_MEDIA_TIZEN_BROWSER_MEDIA_PLAYER_MANAGER_TIZEN_H_ + +#include "base/memory/scoped_vector.h" +#include "content/public/browser/browser_message_filter.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/web_contents_observer.h" +#include "media/base/efl/media_player_manager_efl.h" + +namespace content { + +// This class manages all the MediaPlayerEfl objects. It receives +// control operations from the the render process, and forwards +// them to corresponding MediaPlayerEfl object. Callbacks from +// MediaPlayerEfl objects are converted to IPCs and then sent to the +// render process. +class CONTENT_EXPORT BrowserMediaPlayerManagerEfl + : public media::MediaPlayerManager { + public: + // Returns a new instance using the registered factory if available. + static BrowserMediaPlayerManagerEfl* Create( RenderFrameHost* efh); + virtual ~BrowserMediaPlayerManagerEfl(); + + // media::MediaPlayerManager implementation. + virtual media::MediaPlayerEfl* GetPlayer(int player_id) override; + virtual void OnTimeChanged(int player_id) override; + virtual void OnTimeUpdate(int player_id, double current_time) override; + virtual void OnPauseStateChange(int player_id, bool state) override; + virtual void OnSeekStateChange(int player_id, bool state) override; + virtual void OnRequestSeek(int player_id, double seek_time) override; + virtual void OnBufferUpdate( + int player_id, + std::vector buffer_range) override; + virtual void OnDurationChange(int player_id, double duration) override; + virtual void OnReadyStateChange( + int player_id, + media::MediaPlayerEfl::ReadyState state) override; + virtual void OnNetworkStateChange( + int player_id, + media::MediaPlayerEfl::NetworkState state) override; + virtual void OnMediaDataChange( + int player_id, + int format, + int height, + int width, + int media) override; + virtual void OnNewFrameAvailable( + int player_id, + base::SharedMemoryHandle foreign_memory_handle, + uint32 length, base::TimeDelta timestamp) override; + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + virtual void OnPlatformSurfaceUpdated( + int player_id, + int pixmap_id, + base::TimeDelta timestamp) override; +#endif + + // Helper function to handle IPC from RenderMediaPlayerMangaerEfl. + virtual void OnPlay(int player_id); + virtual void OnPause(int player_id); + virtual void OnSetVolume(int player_id, double volume); + virtual void OnSetRate(int player_id, double rate); + virtual void OnInitialize( + int player_id, + MediaPlayerHostMsg_Initialize_Type type, + const GURL& url, + double volume, + int demuxer_client_id); + virtual void OnDestroy(int player_id); + virtual void OnSeek(int player_id, double time); + + protected: + // Clients must use Create() or subclass constructor. + explicit BrowserMediaPlayerManagerEfl(RenderFrameHost* render_frame_host); + + void AddPlayer(media::MediaPlayerEfl* player); + void RemovePlayer(int player_id); + + // Helper function to send messages to RenderFrameObserver. + bool Send(IPC::Message* msg); + + int GetRoutingID(); + WebContents* web_contents() const { return web_contents_; } + + private: + // An array of managed players. + ScopedVector players_; + RenderFrameHost* render_frame_host_; + WebContents* const web_contents_; + base::WeakPtrFactory weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(BrowserMediaPlayerManagerEfl); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_MEDIA_TIZEN_BROWSER_MEDIA_PLAYER_MANAGER_TIZEN_H_ diff --git a/tizen_src/chromium_impl/content/browser/media/efl/webaudio_decoder_browser_gstreamer.cc b/tizen_src/chromium_impl/content/browser/media/efl/webaudio_decoder_browser_gstreamer.cc new file mode 100644 index 000000000000..1d0a6e0510ba --- /dev/null +++ b/tizen_src/chromium_impl/content/browser/media/efl/webaudio_decoder_browser_gstreamer.cc @@ -0,0 +1,485 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/media/efl/webaudio_decoder_browser_gstreamer.h" + +#include "base/bind.h" +#include "base/strings/string_util.h" +#include "base/time/time.h" +#include "gst/app/gstappsink.h" +#include "gst/audio/audio.h" +#include "media/base/audio_bus.h" +#include "media/base/limits.h" +#include "media/base/efl/webaudio_media_codec_info_efl.h" +#include "third_party/WebKit/public/platform/WebAudioBus.h" + +namespace content { + +#define CHUNK_SIZE 204800 // (4096*50) + +static int gst_dec_count_ = 32; + +#if GST_VERSION_MAJOR == 1 +static int audio_width_ = 16; +const char* kdecodebin = "decodebin"; +#endif + +//////////////////////////////////////// +// GSTDecoder class - declaration +class GSTDecoder { + public: + void InitializeGstDestination(int pcm_output, + uint16_t number_of_channels, + uint32_t sample_rate, + size_t number_of_frames); + void SendGstOutputUsinghandle(int pcm_output, uint8_t* buffer, int buf_size); + static void MediaFileDecoder(GstAppData* appData); + + // callbacks + static void cb_newpad (GstElement* decodebin, GstPad* pad, GstAppData* data); + static void cb_need_data (GstElement* source, guint size, GstAppData* data); + static void cb_eos (GstAppSink* sink, gpointer user_data); + static GstFlowReturn cb_new_preroll (GstAppSink* sink, gpointer user_data); + static GstFlowReturn cb_new_buffer (GstAppSink* sink, gpointer user_data); + static GstBusSyncReply cb_pipeline_message (GstBus* bus, + GstMessage* message, + GstAppData* data); +}; // GSTDecoder class + +void GSTDecoder::InitializeGstDestination(int pcm_output, + uint16_t number_of_channels, + uint32_t sample_rate, + size_t number_of_frames) { + struct media::WebAudioMediaCodecInfoEfl info = { + static_cast(number_of_channels), + static_cast(sample_rate), + static_cast(number_of_frames) + }; + + HANDLE_EINTR(write(pcm_output, &info, sizeof(info))); +} + +void GSTDecoder::SendGstOutputUsinghandle(int pcm_output, uint8_t * buffer, int buf_size) { + size_t count = buf_size; + ssize_t total_bytes = 0; + while (count > 0) { + int bytes_to_write = (count >= PIPE_BUF) ? PIPE_BUF : count; + ssize_t bytes_written = HANDLE_EINTR(write(pcm_output, buffer, bytes_to_write)); + if (bytes_written == -1) + break; + count -= bytes_written; + buffer += bytes_written; + total_bytes += bytes_written; + } + return; +} + +void GSTDecoder::MediaFileDecoder(GstAppData* appData) { + if(!appData) + return; + + if (!gst_is_initialized()) { + GError* err = NULL; + if (!gst_init_check(NULL, NULL, &err)) { + LOG(ERROR) << "Gst could not be initialized"; + close(appData->pcm_output_); + return; + } + } + + // makes gst-element(s) + appData->app_src_ = gst_element_factory_make("appsrc", NULL); + appData->app_sink_ = gst_element_factory_make("appsink", NULL); +#if GST_VERSION_MAJOR == 1 + appData->decoder_ = gst_element_factory_make(kdecodebin, NULL); +#else + appData->decoder_ = gst_element_factory_make("decodebin2", NULL); +#endif + appData->convert_ = gst_element_factory_make("audioconvert", NULL); + + appData->resample_ = gst_element_factory_make ("audioresample", NULL); + appData->capsfilter_ = gst_element_factory_make("capsfilter", NULL); +#if GST_VERSION_MAJOR == 1 + appData->caps_ = gst_caps_new_simple("audio/x-raw", "format", G_TYPE_STRING, + "S16LE", "rate", G_TYPE_INT, 44100, + "channels", G_TYPE_INT, 2, "layout", + G_TYPE_STRING, "interleaved", NULL); +#else + appData->caps_ = gst_caps_new_simple("audio/x-raw-int", "width", G_TYPE_INT, 16, NULL); +#endif + + if (!appData->app_src_ || !appData->app_sink_ || !appData->decoder_ || + !appData->convert_ || !appData->resample_ || !appData->capsfilter_ || + !appData->caps_) { + LOG(ERROR) << "Creation of one or more gst-element(s) for decoder pipeline failed"; + return; + } + + g_object_set(G_OBJECT(appData->capsfilter_), "caps", appData->caps_, NULL); + gst_caps_unref(appData->caps_); + + // sets propeties for element(s) + g_object_set(G_OBJECT(appData->app_sink_), "sync", FALSE, NULL); + + // connects signal(s) to element(s) + g_signal_connect(appData->app_src_, "need-data", G_CALLBACK(cb_need_data), appData); + g_signal_connect(appData->decoder_, "pad-added", G_CALLBACK(cb_newpad), appData); + +#if GST_VERSION_MAJOR == 1 + GstAppSinkCallbacks callbacks = { cb_eos, cb_new_preroll, + cb_new_buffer}; +#else + GstAppSinkCallbacks callbacks = { cb_eos, cb_new_preroll, + cb_new_buffer, NULL, + { NULL, NULL, NULL } }; +#endif + gst_app_sink_set_callbacks(GST_APP_SINK(appData->app_sink_), &callbacks, appData, NULL); + + //FIXME: gst-element(s) can have 94 each name, but this can not be enough + gchar pipeline_name[16] = {0,}; + sprintf(pipeline_name, "pipeln_%d", gst_dec_count_); + + memset(appData->audioout_name_, 0, 16); + sprintf(appData->audioout_name_, "audout_%d", gst_dec_count_); + + gst_dec_count_++; + if (gst_dec_count_ > 126) + gst_dec_count_ = 32; + + // makes gst-pipeline + appData->pipeline_ = gst_pipeline_new((const gchar*)&pipeline_name); + gst_bin_add_many(GST_BIN(appData->pipeline_), appData->app_src_, appData->decoder_, NULL); + if (!gst_element_link(appData->app_src_, appData->decoder_)) { + LOG(ERROR) << __FUNCTION__ << " Something wrong on gst initialization"; + if ( appData->pipeline_ ) + gst_object_unref(appData->pipeline_); + return; + } + + // makes audio-output and links it to gst-pipeline + appData->audioout_ = gst_bin_new(appData->audioout_name_); + appData->audiopad_ = gst_element_get_static_pad(appData->convert_, "sink"); + + gst_bin_add_many(GST_BIN(appData->audioout_), appData->convert_, + appData->resample_, appData->capsfilter_, appData->app_sink_, NULL); + if (!gst_element_link_many(appData->convert_, appData->resample_, + appData->capsfilter_, appData->app_sink_, NULL)) { + LOG(ERROR) << __FUNCTION__ << "Some element could not be linked"; + if ( appData->pipeline_ ) + gst_object_unref(appData->pipeline_); + return; + } + + gst_element_add_pad(appData->audioout_, gst_ghost_pad_new("sink", appData->audiopad_)); + gst_object_unref(appData->audiopad_); + gst_bin_add(GST_BIN(appData->pipeline_), appData->audioout_); + + GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(appData->pipeline_)); + if (!bus) { + LOG(ERROR) << __FUNCTION__ << "GStreamer bus creation failed"; + if ( appData->pipeline_ ) + gst_object_unref(appData->pipeline_); + return; + } +#if GST_VERSION_MAJOR == 1 + gst_bus_set_sync_handler(bus, (GstBusSyncHandler)cb_pipeline_message, appData, + NULL); +#else + gst_bus_set_sync_handler(bus, (GstBusSyncHandler)cb_pipeline_message, appData); +#endif + + // actually works decoding + gst_element_set_state(appData->pipeline_, GST_STATE_PLAYING); + + //FIXME: Check if its possible to remove usleep() and make any gst + //async call so that GST wont block on Browser UI thread. + while (appData->isRunning_) { + usleep(10); + } + + // returns resource(s) + g_signal_handlers_disconnect_by_func( + bus, reinterpret_cast(cb_pipeline_message), appData); +#if GST_VERSION_MAJOR == 1 + gst_bus_set_sync_handler(bus, NULL, NULL, NULL); +#else + gst_bus_set_sync_handler(bus, NULL, NULL); +#endif + gst_object_unref(bus); + gst_element_set_state(appData->pipeline_, GST_STATE_NULL); + gst_object_unref(appData->pipeline_); +} + +void GSTDecoder::cb_newpad(GstElement* decodebin, GstPad* pad, GstAppData* data) { +#if GST_VERSION_MAJOR == 1 + GstPad* sink_pad = gst_element_get_static_pad(data->audioout_, "sink"); +#else + GstPad* sink_pad = gst_element_get_pad(data->audioout_, "sink"); +#endif + if (GST_PAD_IS_LINKED(sink_pad)) { + g_object_unref(sink_pad); + return; + } + + GstCaps* caps = NULL; + GstStructure* str = NULL; + +#if GST_VERSION_MAJOR == 1 + caps = gst_pad_query_caps(pad, NULL); +#else + caps = gst_pad_get_caps(pad); +#endif + if (caps) { + str = gst_caps_get_structure(caps, 0); + if (str) { + if (!g_strrstr(gst_structure_get_name(str), data->audioout_name_)) + gst_pad_link(pad, sink_pad); + } + } + g_object_unref(sink_pad); + gst_caps_unref(caps); +} + +void GSTDecoder::cb_need_data (GstElement* source, guint size, GstAppData* data) { + if (data->isEndOfStream_) + return; + + guint len = CHUNK_SIZE; + if ((data->enc_offset_ + len ) > data->enc_length_) + len = data->enc_length_ - data->enc_offset_; + +#if GST_VERSION_MAJOR == 1 + GstBuffer* buffer = gst_buffer_new_wrapped_full(GST_MEMORY_FLAG_READONLY, + data->encodeddata_ + data->enc_offset_, + len, 0, len, NULL, NULL); + if (!buffer) + { + LOG(ERROR) << __FUNCTION__ << "cb_need_data: buffer creation: FAILED"; + return; + } +#else + GstBuffer* buffer = gst_buffer_new(); + if (!buffer) + return; + + GST_BUFFER_DATA(buffer) = data->encodeddata_ + data->enc_offset_; + GST_BUFFER_SIZE(buffer) = len; +#endif + data->enc_offset_ += len; + + GstFlowReturn ret = GST_FLOW_OK; + g_signal_emit_by_name(data->app_src_, "push-buffer", buffer, &ret); + + if (ret != GST_FLOW_OK) { + LOG(ERROR) << "cb_need_data: push-buffer ret: FAILED"; + data->isRunning_ = false; + } + + if (data->enc_offset_ >= data->enc_length_) { + data->isEndOfStream_ = TRUE; + g_signal_emit_by_name(data->app_src_, "end-of-stream", &ret); + } + + gst_buffer_unref(buffer); +} + +void GSTDecoder::cb_eos (GstAppSink* sink, gpointer user_data) { + GstAppData* data = reinterpret_cast(user_data); + if (!data->isEndOfStream_) { + LOG(ERROR) << "not end of stream yet appsrc-side"; + } + + close(data->pcm_output_); + data->isRunning_ = false; +} + +GstFlowReturn GSTDecoder::cb_new_preroll (GstAppSink* sink, gpointer user_data) { + return GST_FLOW_OK; +} + +GstFlowReturn GSTDecoder::cb_new_buffer (GstAppSink* sink, gpointer user_data) { +#if GST_VERSION_MAJOR == 1 + GstSample* sample = gst_app_sink_pull_sample(sink); + GstBuffer* buffer = gst_sample_get_buffer(sample); +#else + GstBuffer* buffer = gst_app_sink_pull_buffer(GST_APP_SINK(sink)); +#endif + + if (!buffer) + return GST_FLOW_ERROR; + + GstAppData* data = (GstAppData*) (user_data); + + if (data->isNewRequest_) { + GstCaps* caps = NULL; + GstStructure* str = NULL; +#if GST_VERSION_MAJOR == 1 + caps = gst_sample_get_caps(sample); +#else + caps = gst_buffer_get_caps(buffer); +#endif + if (caps) + str = gst_caps_get_structure(caps, 0); + + gboolean ret = true; + gint channel = 0; + gint rate = 0; + gint width = 0; + if (caps && str) { + ret &= gst_structure_get_int(str, "channels", &channel); + ret &= gst_structure_get_int(str, "rate", &rate); +#if !(GST_VERSION_MAJOR == 1) + ret &= gst_structure_get_int(str, "width", &width); +#else + (void)width; +#endif + } + +#if GST_VERSION_MAJOR == 1 + if (!caps || !str || !ret || !channel || !rate) { +#else + if (!caps || !str || !ret || !channel || !rate || !width) { +#endif + gst_caps_unref(caps); + gst_buffer_unref(buffer); + return GST_FLOW_ERROR; + } + +#if GST_VERSION_MAJOR == 1 + GstClockTime duration = (static_cast (gst_buffer_get_size(buffer)) + * 8 * GST_SECOND) / (channel * rate * audio_width_); +#else + GstClockTime duration = (static_cast (GST_BUFFER_SIZE(buffer))*8*GST_SECOND) + / (channel*rate*width); +#endif + int frames = GST_CLOCK_TIME_TO_FRAMES(duration, rate); + + data->gst_decoder_->InitializeGstDestination(data->pcm_output_, channel, rate, frames); + data->isNewRequest_ = false; + } + +#if GST_VERSION_MAJOR == 1 + GstMapInfo gst_map; + gst_buffer_map(buffer, &gst_map, (GstMapFlags)(GST_MAP_READ)); + if (buffer && gst_map.size > 0) { + data->gst_decoder_->SendGstOutputUsinghandle(data->pcm_output_, + gst_map.data, + gst_map.size); + gst_buffer_unmap(buffer, &gst_map); +#else + if (buffer && buffer->size > 0) { + data->gst_decoder_->SendGstOutputUsinghandle(data->pcm_output_, + buffer->data, + buffer->size); +#endif + } + + gst_buffer_unref(buffer); + return GST_FLOW_OK; +} + +GstBusSyncReply GSTDecoder::cb_pipeline_message(GstBus* bus, + GstMessage* message, + GstAppData* data) { + switch (GST_MESSAGE_TYPE(message)) { + case GST_MESSAGE_ERROR: + GError* error; + gst_message_parse_error(message, &error, NULL); + LOG(ERROR) << "Error message : " << error->message + << " recieved from : "<< GST_MESSAGE_SRC_NAME(message) + << ", error code : " << error->code; + g_error_free(error); + + if (data->isRunning_) { + close(data->pcm_output_); + data->isRunning_ = false; + } + break; + default: + LOG(WARNING) << "Unhandled GStreamer message type : " + << GST_MESSAGE_TYPE_NAME(message); + break; + } + + gst_message_unref(message); + + return GST_BUS_DROP; +} + +//////////////////////////////////////// +// BrowserMessageFilterEfl class + +// static +BrowserMessageFilterEfl* BrowserMessageFilterEfl::GetInstance() { + return Singleton::get(); +} + +BrowserMessageFilterEfl::BrowserMessageFilterEfl() + : gst_thread_("GstThread") { +} + +BrowserMessageFilterEfl::~BrowserMessageFilterEfl() { +} + +void BrowserMessageFilterEfl::DecodeUsingGST( + base::SharedMemoryHandle foreign_memory_handle, + base::FileDescriptor pcm_output, + uint32_t data_size) { + + base::SharedMemory shared_memory(foreign_memory_handle, false); + shared_memory.Map(data_size); + + GstAppData* data = new GstAppData; + if (!data) + return; + + memset(data, 0, sizeof(GstAppData)); + + data->encodeddata_ = (uint8_t*) (malloc(data_size)); + if (!data->encodeddata_) { + LOG(ERROR) << "BrowserMessageFilterEfl::"<<__FUNCTION__ + << " - encodeddata malloc failed"; + delete data; + return; + } + memcpy(data->encodeddata_, static_cast(shared_memory.memory()), data_size); + + data->isRunning_ = true; + data->enc_length_ = data_size; + data->pcm_output_ = pcm_output.fd; + data->isEndOfStream_ = false; + data->isNewRequest_ = true; + + GSTDecoder *decoder = new GSTDecoder(); + if (decoder) { + data->gst_decoder_ = decoder; + decoder->MediaFileDecoder(data); + delete decoder; + } + + if (data->encodeddata_) { + free(data->encodeddata_); + data->encodeddata_ = NULL; + } + delete data; +} + +void BrowserMessageFilterEfl::EncodedDataReceived( + base::SharedMemoryHandle foreign_memory_handle, + base::FileDescriptor pcm_output, + uint32_t data_size) { + + if (!gst_thread_.IsRunning() && !gst_thread_.Start()) { + LOG(ERROR) << "BrowserMessageFilterEfl::"<<__FUNCTION__ + << " - Starting GStreamer thread failed"; + return; + } + + gst_thread_.message_loop()->PostTask(FROM_HERE, + base::Bind(&BrowserMessageFilterEfl::DecodeUsingGST, + base::Unretained(this), foreign_memory_handle, + pcm_output, data_size)); +} + +} // namespace content diff --git a/tizen_src/chromium_impl/content/browser/media/efl/webaudio_decoder_browser_gstreamer.h b/tizen_src/chromium_impl/content/browser/media/efl/webaudio_decoder_browser_gstreamer.h new file mode 100644 index 000000000000..019a0c67ce23 --- /dev/null +++ b/tizen_src/chromium_impl/content/browser/media/efl/webaudio_decoder_browser_gstreamer.h @@ -0,0 +1,70 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_MEDIA_TIZEN_WEBAUDIO_DECODER_BROWSER_GSTREAMER_H_ +#define CONTENT_BROWSER_MEDIA_TIZEN_WEBAUDIO_DECODER_BROWSER_GSTREAMER_H_ + +#include "base/basictypes.h" +#include "base/memory/singleton.h" +#include "base/memory/shared_memory.h" +#include "base/threading/thread.h" +#include "content/common/content_export.h" +#include +#include + +namespace content { + +class GSTDecoder; + +// GstAppData struct +typedef struct _GstAppData { + GstElement *pipeline_; + GstElement *app_src_, *app_sink_; + GstElement *decoder_, *convert_, *resample_, *capsfilter_; + GstCaps *caps_; + GstElement *audioout_; + GstElement *audio_; + GstPad *audiopad_; + + gchar audioout_name_[16]; + + bool isRunning_; + + guint sourceid_; // To control the GSource + guint8 *encodeddata_; + gsize enc_length_; + guint64 enc_offset_; + + int pcm_output_; + bool isEndOfStream_; + bool isNewRequest_; + + GSTDecoder *gst_decoder_; +} GstAppData; + +// BrowserMessageFilterEfl class +class CONTENT_EXPORT BrowserMessageFilterEfl { + public: + static BrowserMessageFilterEfl* GetInstance(); + + void EncodedDataReceived(base::SharedMemoryHandle foreign_memory_handle, + base::FileDescriptor pcm_output, + uint32_t data_size); + + private: + friend struct DefaultSingletonTraits; + BrowserMessageFilterEfl(); + virtual ~BrowserMessageFilterEfl(); + void DecodeUsingGST(base::SharedMemoryHandle foreign_memory_handle, + base::FileDescriptor pcm_output, + uint32_t data_size); + + base::Thread gst_thread_; + + DISALLOW_COPY_AND_ASSIGN(BrowserMessageFilterEfl); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_MEDIA_TIZEN_WEBAUDIO_DECODER_BROWSER_GSTREAMER_H_ diff --git a/tizen_src/chromium_impl/content/browser/media/media_web_contents_observer_efl.cc b/tizen_src/chromium_impl/content/browser/media/media_web_contents_observer_efl.cc new file mode 100644 index 000000000000..75b075021e08 --- /dev/null +++ b/tizen_src/chromium_impl/content/browser/media/media_web_contents_observer_efl.cc @@ -0,0 +1,89 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/media/media_web_contents_observer_efl.h" + +#include "content/browser/media/efl/browser_media_player_manager_efl.h" +#include "content/browser/renderer_host/render_process_host_impl.h" +#include "content/common/media/efl/media_player_messages_efl.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/web_contents.h" +#include "ipc/ipc_message_macros.h" + +namespace content { + +MediaWebContentsObserverEfl::MediaWebContentsObserverEfl( + RenderViewHost* render_view_host) + : WebContentsObserver(WebContents::FromRenderViewHost(render_view_host)) { +} + +MediaWebContentsObserverEfl::~MediaWebContentsObserverEfl() { +} + +void MediaWebContentsObserverEfl::RenderFrameDeleted( + RenderFrameHost* render_frame_host) { + uintptr_t key = reinterpret_cast(render_frame_host); + media_player_managers_.erase(key); +} + + +bool MediaWebContentsObserverEfl::OnMessageReceived(const IPC::Message& msg, + RenderFrameHost* render_frame_host) { + return OnMediaPlayerMessageReceived(msg, render_frame_host); +} + +bool MediaWebContentsObserverEfl::OnMediaPlayerMessageReceived( + const IPC::Message& msg, + RenderFrameHost* render_frame_host) { + bool handled = true; + + IPC_BEGIN_MESSAGE_MAP(MediaWebContentsObserverEfl, msg) + IPC_MESSAGE_FORWARD(MediaPlayerGstHostMsg_Init, + GetMediaPlayerManager(render_frame_host), + BrowserMediaPlayerManagerEfl::OnInitialize) + + IPC_MESSAGE_FORWARD(MediaPlayerGstHostMsg_DeInit, + GetMediaPlayerManager(render_frame_host), + BrowserMediaPlayerManagerEfl::OnDestroy) + + IPC_MESSAGE_FORWARD(MediaPlayerGstHostMsg_Play, + GetMediaPlayerManager(render_frame_host), + BrowserMediaPlayerManagerEfl::OnPlay) + + IPC_MESSAGE_FORWARD(MediaPlayerGstHostMsg_Pause, + GetMediaPlayerManager(render_frame_host), + BrowserMediaPlayerManagerEfl::OnPause) + + IPC_MESSAGE_FORWARD(MediaPlayerGstHostMsg_SetVolume, + GetMediaPlayerManager(render_frame_host), + BrowserMediaPlayerManagerEfl::OnSetVolume) + + IPC_MESSAGE_FORWARD(MediaPlayerGstHostMsg_SetRate, + GetMediaPlayerManager(render_frame_host), + BrowserMediaPlayerManagerEfl::OnSetRate) + + IPC_MESSAGE_FORWARD(MediaPlayerGstHostMsg_Seek, + GetMediaPlayerManager(render_frame_host), + BrowserMediaPlayerManagerEfl::OnSeek) + + IPC_MESSAGE_UNHANDLED(handled = false) + + IPC_END_MESSAGE_MAP() + return handled; +} + +BrowserMediaPlayerManagerEfl* + MediaWebContentsObserverEfl::GetMediaPlayerManager( + RenderFrameHost* render_frame_host) { + uintptr_t key = reinterpret_cast(render_frame_host); + if (!media_player_managers_.contains(key)) { + media_player_managers_.set( + key, + make_scoped_ptr( + BrowserMediaPlayerManagerEfl::Create(render_frame_host))); + } + return media_player_managers_.get(key); +} + +} // namespace content diff --git a/tizen_src/chromium_impl/content/browser/media/media_web_contents_observer_efl.h b/tizen_src/chromium_impl/content/browser/media/media_web_contents_observer_efl.h new file mode 100644 index 000000000000..909a76778d24 --- /dev/null +++ b/tizen_src/chromium_impl/content/browser/media/media_web_contents_observer_efl.h @@ -0,0 +1,54 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_MEDIA_MEDIA_WEB_CONTENTS_OBSERVER_EFL_H_ +#define CONTENT_BROWSER_MEDIA_MEDIA_WEB_CONTENTS_OBSERVER_EFL_H_ + +#include "base/compiler_specific.h" +#include "base/containers/scoped_ptr_hash_map.h" +#include "content/common/content_export.h" +#include "content/public/browser/web_contents_observer.h" + +namespace content { + +class BrowserMediaPlayerManagerEfl; +class RenderViewHost; + +// This class manages all RenderFrame based media related managers at the +// browser side. It receives IPC messages from media RenderFrameObservers and +// forwards them to the corresponding managers. The managers are responsible +// for sending IPCs back to the RenderFrameObservers at the render side. +class CONTENT_EXPORT MediaWebContentsObserverEfl + : public WebContentsObserver { + public: + explicit MediaWebContentsObserverEfl(RenderViewHost* render_view_host); + virtual ~MediaWebContentsObserverEfl(); + + // WebContentsObserver implementations. + virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) override; + virtual bool OnMessageReceived(const IPC::Message& message, + RenderFrameHost* render_frame_host) override; + + // Helper functions to handle media player IPC messages. Returns whether the + // |message| is handled in the function. + bool OnMediaPlayerMessageReceived(const IPC::Message& message, + RenderFrameHost* render_frame_host); + + // Gets the media player manager associated with |render_frame_host|. Creates + // a new one if it doesn't exist. The caller doesn't own the returned pointer. + BrowserMediaPlayerManagerEfl* GetMediaPlayerManager( + RenderFrameHost* render_frame_host); + + private: + // Map from RenderFrameHost* to BrowserMediaPlayerManagerEfl. + typedef base::ScopedPtrHashMap + MediaPlayerManagerMap; + MediaPlayerManagerMap media_player_managers_; + + DISALLOW_COPY_AND_ASSIGN(MediaWebContentsObserverEfl); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_MEDIA_MEDIA_WEB_CONTENTS_OBSERVER_EFL_H_ diff --git a/tizen_src/chromium_impl/content/common/cache_params_efl.h b/tizen_src/chromium_impl/content/common/cache_params_efl.h new file mode 100644 index 000000000000..449d1e385059 --- /dev/null +++ b/tizen_src/chromium_impl/content/common/cache_params_efl.h @@ -0,0 +1,20 @@ +// Copyright 2014 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CACHE_PARAMS_EFL_H_ +#define CACHE_PARAMS_EFL_H_ + +struct CacheParamsEfl { + int64 cache_total_capacity; + int64 cache_min_dead_capacity; + int64 cache_max_dead_capacity; +#if 0 + double dead_decoded_data_deletion_interval; + int64 page_cache_capacity; + int64 url_cache_memory_capacity; + int64 url_cache_disk_capacity; +#endif +}; + +#endif /* CACHE_PARAMS_EFL_H_ */ diff --git a/tizen_src/chromium_impl/content/common/gpu/media/efl/tizen_video_decode_accelerator.cc b/tizen_src/chromium_impl/content/common/gpu/media/efl/tizen_video_decode_accelerator.cc new file mode 100644 index 000000000000..a7b7ce510a4c --- /dev/null +++ b/tizen_src/chromium_impl/content/common/gpu/media/efl/tizen_video_decode_accelerator.cc @@ -0,0 +1,936 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/common/gpu/media/efl/tizen_video_decode_accelerator.h" + +#include +#include +#include +#include +#include + +#include "base/bind.h" +#include "base/memory/shared_memory.h" +#include "base/message_loop/message_loop_proxy.h" +#include "base/synchronization/waitable_event.h" +#include "base/time/time.h" +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +#include "ui/gl/efl_pixmap.h" +#else +#include "base/process/process.h" +#endif + +#if GST_VERSION_MAJOR == 1 +#include +#else +#include +#endif + +using media::VideoFrame; + +namespace { + +struct GstElementDeleter { + void operator()(GstElement* ptr) const { + DCHECK(ptr != NULL); + gst_object_unref(ptr); + } +}; + +// Gstreamer elements and names. +#if defined(OS_TIZEN) +const char* kDecoderName = "decoder"; +#if GST_VERSION_MAJOR == 1 +const char* kDecoderGstElement = "omxh264dec"; +#else +const char* kDecoderGstElement = "omx_h264dec"; +#endif +#endif // OS_TIZEN + +// Generating Unique Key from given width and height. +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +int32 ConvertWidthAndHeightToKey(int width, int height) { + return ((width << 16) | height); +} +#endif // TIZEN_MULTIMEDIA_PIXMAP_SUPPORT +} // namespace + +namespace content { + +enum { + MAX_BITRATE = 2000000, // bps. + INPUT_BUFFER_SIZE = MAX_BITRATE / 8, // bytes. 1 sec for H.264 HD video. + ID_LAST = 0x3FFFFFFF, // wrap round ID after this +}; + +media::VideoDecodeAccelerator* CreateTizenVideoDecodeAccelerator() { + return new TizenVideoDecodeAccelerator(); +} + +struct TizenVideoDecodeAccelerator::BitstreamBufferRef { + BitstreamBufferRef( + base::WeakPtr client, + const scoped_refptr& client_message_loop_proxy, + base::SharedMemory* shm, + size_t size, + int32 input_id) + : client_(client), + client_message_loop_proxy_(client_message_loop_proxy), + shm_(shm), + size_(size), + bytes_used_(0), + input_id_(input_id), + gst_buffer_(NULL) {} + + ~BitstreamBufferRef() { + if (input_id_ >= 0) { + client_message_loop_proxy_->PostTask( + FROM_HERE, + base::Bind( + &media::VideoDecodeAccelerator::Client::NotifyEndOfBitstreamBuffer, + client_, + input_id_)); + } + } + + static void Destruct(gpointer data) { + DCHECK(data != NULL); + BitstreamBufferRef* pRef = static_cast(data); + delete pRef; + } + + base::WeakPtr client_; + scoped_refptr client_message_loop_proxy_; + scoped_ptr shm_; + size_t size_; + off_t bytes_used_; + int32 input_id_; + GstBuffer* gst_buffer_; +}; + +struct TizenVideoDecodeAccelerator::Impl { + Impl() + : can_feed_(true), + is_destroying_(false), + pipeline_(NULL), + sink_(NULL), + appsrc_(NULL), + io_message_loop_proxy_(base::MessageLoopProxy::current()), + gst_thread_("TizenDecoderThreadGst"), + bitstream_buffer_id_(0) +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + ,pixmap_id_(0), + gst_width_(0), + gst_height_(0), + damage_(0), + damage_handler_(NULL), + is_x_window_handle_set_(false) +#else + ,caps_width_(0), + caps_height_(0) +#endif +{ +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + xpixmap_buffer_map_.clear(); +#endif +} + +#if !defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + static GstFlowReturn OnDecoded(GstAppSink* sink, gpointer app_data); + void DeliverVideoFrame(GstBuffer* buffer, + int32 bitstream_buffer_id, + gfx::Rect frame_size); + void CreateAppSinkElement(); + static void OnSinkCapChanged( + GstPad* sink_pad, GParamSpec* gparamspec, void* user_data); +#endif + + static GstBusSyncReply OnBusMessage( + GstBus* bus, GstMessage* msg, gpointer data) { + switch (GST_MESSAGE_TYPE(msg)) { + case GST_MESSAGE_ERROR: { + gchar* debug = NULL; + GError* error = NULL; + gst_message_parse_error(msg, &error, &debug); + LOG(ERROR) << __FUNCTION__ + << " GSTError happens from bus at " + << GST_OBJECT_NAME(msg->src) + << ":" << error->message; + LOG(ERROR) << __FUNCTION__ + << " Debugging Info: " + << (debug != NULL ? debug : "none"); + g_error_free(error); + g_free(debug); + break; + } +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + case GST_MESSAGE_ELEMENT: { + TizenVideoDecodeAccelerator::Impl* obj_impl = + static_cast(data); + if (obj_impl) { + if (obj_impl->IsXWindowHandleSet()) { +#if GST_VERSION_MAJOR == 1 + if (gst_is_video_overlay_prepare_window_handle_message(msg)) { +#else + if (gst_structure_has_name(msg->structure, "prepare-xid")) { +#endif + obj_impl->OnXWindowIdPrepared(msg); + gst_message_unref(msg); + return GST_BUS_PASS; + } + } + } else { + LOG(ERROR) << __FUNCTION__ << "Accelerator is NULL"; + } + break; + } +#endif + default: + break; + } + return GST_BUS_PASS; + } + + static void StartFeed(GstAppSrc *source, guint size, gpointer app) { + DCHECK(source); + content::TizenVideoDecodeAccelerator::Impl* impl = + static_cast(app); + impl->can_feed_ = true; + } + + static void StopFeed(GstAppSrc *source, gpointer app) { + DCHECK(source); + content::TizenVideoDecodeAccelerator::Impl* impl = + static_cast(app); + impl->can_feed_ = false; + } + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + bool IsXWindowHandleSet() const {return is_x_window_handle_set_;} + void OnXWindowIdPrepared(GstMessage* message); + void SetXWindowHandle(bool handle_set); + void SetPixmap(const int32& gst_width, const int32& gst_height); + void DeregisterDamageHandler(); + static Eina_Bool OnSurfaceChanged(void* ptr_acc, int type, void* event); + static void OnSinkCapChanged( + GstPad* sink_pad, GParamSpec* gparamspec, void* user_data); +#endif + + volatile bool can_feed_; + volatile bool is_destroying_; + GstElement* pipeline_; + GstElement* sink_; + GstElement* appsrc_; + scoped_refptr io_message_loop_proxy_; + scoped_ptr > io_client_weak_factory_; + base::Thread gst_thread_; + int bitstream_buffer_id_; +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + scoped_refptr pixmap_surface_; + int pixmap_id_; + gint gst_width_; + gint gst_height_; + Ecore_X_Damage damage_; + Ecore_Event_Handler* damage_handler_; + bool is_x_window_handle_set_; + typedef std::map > PixmapSurfaceTizenMap; + PixmapSurfaceTizenMap xpixmap_buffer_map_; +#else + int caps_width_; + int caps_height_; +#endif +}; + +TizenVideoDecodeAccelerator::TizenVideoDecodeAccelerator() + : impl_(NULL) { +} + +TizenVideoDecodeAccelerator::~TizenVideoDecodeAccelerator() { +} + +bool TizenVideoDecodeAccelerator::Initialize( + media::VideoCodecProfile profile, + Client* client) { + GError* error = NULL; + GstCaps* video_caps = NULL; + GstElement* gst_decoder = NULL; + GstBus* gst_bus = NULL; +#if defined(OS_TIZEN) + GstPad* video_sink_pad = NULL; + GstElement* gst_parser = NULL; +#if !defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + GstElement* video_filter_ = NULL; + GstElement* gst_converter = NULL; +#endif +#endif + scoped_ptr gst_pipeline; + static GstAppSrcCallbacks appsrc_callbacks = + {&Impl::StartFeed, &Impl::StopFeed, NULL}; + CHECK(impl_ == NULL); + impl_ = new Impl(); + impl_->io_client_weak_factory_.reset( + new base::WeakPtrFactory(client)); + + switch (profile) { + case media::H264PROFILE_BASELINE: + DVLOG(1) << "Initialize(): profile -> H264PROFILE_BASELINE"; + break; + case media::H264PROFILE_MAIN: + DVLOG(1) << "Initialize(): profile -> H264PROFILE_MAIN"; + break; + default: + LOG(ERROR) << "Initialize(): unsupported profile=" << profile; + return false; + }; + + if (!gst_is_initialized() && !gst_init_check(NULL, NULL, &error)) { + LOG(ERROR) << __FUNCTION__ << "cannot initialize gstreamer."; + g_error_free(error); + return false; + } + + // pipeline initialization. + gst_pipeline.reset(gst_pipeline_new("h264_decode")); + if (!gst_pipeline) { + LOG(ERROR) << __FUNCTION__ << "cannot initialize gst pipeline."; + return false; + } + if (!(gst_bus = gst_pipeline_get_bus(GST_PIPELINE(gst_pipeline.get())))) { + return false; + } +#if GST_VERSION_MAJOR == 1 + gst_bus_set_sync_handler(gst_bus, Impl::OnBusMessage, impl_, NULL); +#else + gst_bus_set_sync_handler(gst_bus, Impl::OnBusMessage, impl_); +#endif + gst_object_unref(gst_bus); + + // appsrc initialization. + if (!(impl_->appsrc_ = gst_element_factory_make("appsrc", "src"))) { + LOG(ERROR) << __FUNCTION__ << "cannot initialize gst appsrc."; + return false; + } + if (!gst_bin_add(GST_BIN(gst_pipeline.get()), impl_->appsrc_)) { + gst_object_unref(impl_->appsrc_); + impl_->appsrc_ = NULL; + return false; + } + gst_app_src_set_max_bytes(GST_APP_SRC(impl_->appsrc_), INPUT_BUFFER_SIZE); + gst_app_src_set_callbacks(GST_APP_SRC(impl_->appsrc_), &appsrc_callbacks, + static_cast(impl_), NULL); + g_object_set(G_OBJECT(impl_->appsrc_), + "is-live", TRUE, + "block", FALSE, + "min-percent", 80, // if buffer below 80%, need-data emits. + "stream-type", GST_APP_STREAM_TYPE_STREAM, + NULL); + if (!(video_caps = gst_caps_from_string("video/x-h264,framerate=30/1"))) { + return false; + } + gst_app_src_set_caps(GST_APP_SRC(impl_->appsrc_), video_caps); + gst_caps_unref(video_caps); + +#if defined(OS_TIZEN) + DVLOG(1) << "######################################"; + DVLOG(1) << " USING omx_h264dec DECODER " << (unsigned int)this; + DVLOG(1) << "######################################"; + + // parser initialization + if (!(gst_parser = gst_element_factory_make("h264parse", "h264parse"))) { + LOG(ERROR) << " cannot create h264parse."; + return false; + } + if(!gst_bin_add(GST_BIN(gst_pipeline.get()), gst_parser)) { + LOG(ERROR) << " cannot add h264parse into decoder pipeline."; + gst_object_unref(gst_parser); + return false; + } + + // decoder initialization. + if (!(gst_decoder = gst_element_factory_make(kDecoderGstElement, kDecoderName))) { + LOG(ERROR) << " cannot create " << kDecoderGstElement << "."; + return false; + } + if (!gst_bin_add(GST_BIN(gst_pipeline.get()), gst_decoder)) { + LOG(ERROR) << " cannot add " << kDecoderGstElement << " to pipeline."; + gst_object_unref(gst_decoder); + return false; + } +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + // sink initialization. + if (!(impl_->sink_ = gst_element_factory_make("xvimagesink", "xvimagesink"))) { + LOG(ERROR) << __FUNCTION__ << " cannot create xvimagesink."; + return false; + } + if (!gst_bin_add(GST_BIN(gst_pipeline.get()), impl_->sink_)) { + gst_object_unref(impl_->sink_); + impl_->sink_ = NULL; + return false; + } + g_object_set(impl_->sink_, "rotate", 0, NULL); + + if (!(video_sink_pad = gst_element_get_static_pad(impl_->sink_, "sink"))) { + return false; + } + g_signal_connect(video_sink_pad, "notify::caps", + G_CALLBACK(impl_->OnSinkCapChanged), + impl_); + impl_->SetXWindowHandle(false); + gst_object_unref(video_sink_pad); + + // linking the elements. + if (!gst_element_link(impl_->appsrc_, gst_parser)) { + LOG(ERROR) << " Source and gst_parser could not be linked"; + return false; + } + + if (!gst_element_link(gst_parser, gst_decoder)) { + LOG(ERROR) << " gst_parser and Decoder could not be linked"; + return false; + } + if (!gst_element_link(gst_decoder, impl_->sink_)) { + LOG(ERROR) << __FUNCTION__ << " Decoder and Sink could not be linked"; + return false; + } +#else + impl_->CreateAppSinkElement(); + if (!impl_->sink_) { + LOG(ERROR) << "Could not create and add appsink element"; + return false; + } + if (!gst_bin_add(GST_BIN(gst_pipeline.get()), impl_->sink_)) { + gst_object_unref(impl_->sink_); + impl_->sink_ = NULL; + return false; + } + if (!(gst_converter = gst_element_factory_make("fimcconvert", "cvt"))) { + LOG(ERROR) << __FUNCTION__ << " cannot create fimcconvert."; + return false; + } + if(!gst_bin_add(GST_BIN(gst_pipeline.get()), gst_converter)) { + LOG(ERROR) << __FUNCTION__ << " cannot add fimcconvert into pipeline."; + gst_object_unref(gst_converter); + return false; + } + if (!(video_filter_ = gst_element_factory_make("capsfilter", "VideoFilter"))) { + LOG(ERROR) << __FUNCTION__ << " cannot create capsfilter."; + return false; + } + if(!gst_bin_add(GST_BIN(gst_pipeline.get()), video_filter_)) { + LOG(ERROR) << __FUNCTION__ << " cannot add videoFilter into pipeline."; + gst_object_unref(video_filter_); + return false; + } + + // FIXME: SONAL + // OnSinkCapChanged callback is not coming for Appsink implementation + if (!(video_sink_pad = + gst_element_get_static_pad(impl_->sink_, "sink"))) { + LOG(ERROR) << "Could not create video sink pad"; + return false; + } + g_signal_connect( + video_sink_pad, "notify::caps", + G_CALLBACK(&Impl::OnSinkCapChanged), impl_); + gst_object_unref(video_sink_pad); + if (!gst_element_link_many(impl_->appsrc_, + gst_parser, + gst_decoder, + gst_converter, + video_filter_, + impl_->sink_, + NULL)) { + LOG(ERROR) << __FUNCTION__ << " cannot link some elements in decode pipeline"; + return false; + } + g_object_set(G_OBJECT(video_filter_), + "caps", + gst_caps_new_simple("video/x-raw","format", G_TYPE_STRING, "I420",NULL), + NULL); +#endif +#else + DVLOG(1) << "######################################"; + DVLOG(1) << " USING ffdec_h264 DECODER"; + DVLOG(1) << "######################################"; + GstElement* gst_colorspace = NULL; + + // decoder initialization + if (!(gst_decoder = gst_element_factory_make("ffdec_h264", "H264-decoder"))) { + LOG(ERROR) << __FUNCTION__ << " cannot create ffdec_h264."; + return false; + } + if (!gst_bin_add(GST_BIN(gst_pipeline.get()), gst_decoder)) { + gst_object_unref(gst_decoder); + return false; + } + + // colorspace initialization + if (!(gst_colorspace = gst_element_factory_make("ffmpegcolorspace", "cs"))) { + LOG(ERROR) << __FUNCTION__ << " cannot create ffmpegcolorspace."; + return false; + } + if (!gst_bin_add(GST_BIN(gst_pipeline.get()), gst_colorspace)) { + gst_object_unref(gst_colorspace); + return false; + } + + if (!(impl_->sink_ = gst_element_factory_make("autovideosink", "sink"))) { + LOG(ERROR) << __FUNCTION__ << " cannot create autovideosink."; + return false; + } + if (!gst_bin_add(GST_BIN(gst_pipeline.get()), impl_->sink_)) { + gst_object_unref(impl_->sink_); + impl_->sink_ = NULL; + return false; + } + + if(!gst_element_link_many(impl_->appsrc_, gst_decoder, gst_colorspace, + impl_->sink_, NULL)) { + LOG(ERROR) << __FUNCTION__ << " Some element could not be linked"; + return false; + } +#endif + if (!impl_->gst_thread_.Start()) { + LOG(ERROR) << __FUNCTION__ << " gst_thread_ failed to start"; + return false; + } + + impl_->gst_thread_.message_loop()->PostTask( + FROM_HERE, + base::Bind(&TizenVideoDecodeAccelerator::StartDecoder, + base::Unretained(this))); + + GST_DEBUG_BIN_TO_DOT_FILE( + GST_BIN(gst_pipeline.get()), GST_DEBUG_GRAPH_SHOW_ALL, "decoder_graph.dot"); + + impl_->pipeline_ = gst_pipeline.release(); + return true; +} + +void TizenVideoDecodeAccelerator::Decode( + const media::BitstreamBuffer& bitstream_buffer) { + scoped_ptr buffer_ref; + scoped_ptr shm( + new base::SharedMemory(bitstream_buffer.handle(), true)); + + if (!shm->Map(bitstream_buffer.size())) { + LOG(ERROR) << __FUNCTION__ << " could not map bitstream_buffer"; + NotifyError(media::VideoDecodeAccelerator::UNREADABLE_INPUT); + return; + } + + buffer_ref.reset(new BitstreamBufferRef( + impl_->io_client_weak_factory_->GetWeakPtr(), + base::MessageLoopProxy::current(), + shm.release(), + bitstream_buffer.size(), + bitstream_buffer.id())); + + if (!buffer_ref) { + return; + } + + if (impl_->can_feed_ && !impl_->is_destroying_) { + impl_->gst_thread_.message_loop()->PostTask( + FROM_HERE, + base::Bind(&TizenVideoDecodeAccelerator::OnDecode, + base::Unretained(this), + base::Passed(&buffer_ref))); + } else { + DVLOG(2) << __FUNCTION__ + << " Frame drop on decoder:" + << " INPUT Q is FULL"; + } +} + +void TizenVideoDecodeAccelerator::AssignPictureBuffers( + const std::vector& buffers) { + NOTIMPLEMENTED(); +} + +void TizenVideoDecodeAccelerator::ReusePictureBuffer( + int32 picture_buffer_id) { + NOTIMPLEMENTED(); +} + +void TizenVideoDecodeAccelerator::Flush() { + NOTIMPLEMENTED(); +} + +void TizenVideoDecodeAccelerator::Reset() { + NOTIMPLEMENTED(); +} + +void TizenVideoDecodeAccelerator::Destroy() { + if (impl_ != NULL) { +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + impl_->SetXWindowHandle(false); + impl_->DeregisterDamageHandler(); + impl_->xpixmap_buffer_map_.clear(); +#endif + if (impl_->gst_thread_.IsRunning()) { + impl_->gst_thread_.Stop(); + } + gst_app_src_end_of_stream(GST_APP_SRC(impl_->appsrc_)); + impl_->is_destroying_ = true; + if (impl_->pipeline_) { + gst_element_set_state(impl_->pipeline_, GST_STATE_NULL); + gst_object_unref(GST_OBJECT(impl_->pipeline_)); + } + delete impl_; + impl_ = NULL; + } + delete this; +} + +bool TizenVideoDecodeAccelerator::CanDecodeOnIOThread(){ + return false; +} + +void TizenVideoDecodeAccelerator::StartDecoder() { + gst_element_set_state(impl_->pipeline_, GST_STATE_PLAYING); +}; + +#if !defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +void TizenVideoDecodeAccelerator::Impl::OnSinkCapChanged( + GstPad* sink_pad, GParamSpec* gparamspec, void* user_data) { + content::TizenVideoDecodeAccelerator::Impl* impl = + static_cast(user_data); + int width = 0, height = 0; +#if GST_VERSION_MAJOR == 1 + GstCaps* caps = gst_pad_get_current_caps(GST_PAD(sink_pad)); + if (caps) { + GstVideoInfo info; + gst_video_info_init(&info); + if (gst_video_info_from_caps(&info, caps)) { + if ((impl->caps_width_ != width) || (impl->caps_height_ != height)) { + impl->caps_width_ = info.width; + impl->caps_height_ = info.height; + } + } + } +#else + if (gst_video_get_size(sink_pad, &width, &height)) { + if ((impl->caps_width_ != width) || (impl->caps_height_ != height)) { + impl->caps_width_ = width; + impl->caps_height_ = height; + } + } +#endif +} + +GstFlowReturn TizenVideoDecodeAccelerator::Impl::OnDecoded( + GstAppSink* sink, gpointer app_data) { + GstBuffer* gst_output_buf = NULL; + content::TizenVideoDecodeAccelerator::Impl* self = + static_cast(app_data); + // FIXME: SONAL + // Once OnSinkCapChanged callback startes coming dont find height + // and width for all buffers, move this code under if block +#if GST_VERSION_MAJOR == 1 + GstSample* sample = gst_app_sink_pull_sample(GST_APP_SINK(sink)); + gst_output_buf = gst_sample_get_buffer(sample); + GstMapInfo map; + if (!gst_buffer_map(gst_output_buf, &map, GST_MAP_READ)) + LOG (ERROR) << "Decoded Buffer contains invalid or no info!"; + GstCaps* caps = gst_sample_get_caps(sample); +#else + gst_output_buf = gst_app_sink_pull_buffer(GST_APP_SINK(sink)); + GstCaps* caps = gst_buffer_get_caps(GST_BUFFER(gst_output_buf)); +#endif + if (!self->caps_width_ || !self->caps_height_) { + if (!caps) { + LOG(ERROR) << __FUNCTION__ << "Could not fetch caps from buffer"; + gst_buffer_unref(gst_output_buf); + return GST_FLOW_ERROR; + } else { + // No need to unref |GstStructure| + const GstStructure* str = gst_caps_get_structure(caps, 0); + if (!str) { + gst_buffer_unref(gst_output_buf); + gst_caps_unref(caps); + return GST_FLOW_ERROR; + } + if (!gst_structure_get_int(str, "width", &self->caps_width_) || + !gst_structure_get_int(str, "height", &self->caps_height_)) { + LOG(ERROR) << "Buffer information could not be obtained"; + gst_buffer_unref(gst_output_buf); + gst_caps_unref(caps); + return GST_FLOW_ERROR; + } + gst_caps_unref(caps); + } + } + + if (gst_output_buf) { +#if GST_VERSION_MAJOR == 1 + if (map.data) { +#else + if (gst_output_buf->data) { +#endif + gfx::Rect frame_size = + gfx::Rect(self->caps_width_, self->caps_height_); + self->gst_thread_.message_loop()->PostTask( + FROM_HERE, + base::Bind(&TizenVideoDecodeAccelerator::Impl::DeliverVideoFrame, + base::Unretained(self), + gst_output_buf, + self->bitstream_buffer_id_, + frame_size)); + self->bitstream_buffer_id_ = (self->bitstream_buffer_id_ + 1) & ID_LAST; + } + } else { + gst_buffer_unref(gst_output_buf); +#if GST_VERSION_MAJOR == 1 + gst_sample_unref(sample); +#endif + LOG(ERROR) << __FUNCTION__ + << " DECODING FRAME FAILED : frame_id" + << self->bitstream_buffer_id_; + } +#if GST_VERSION_MAJOR == 1 + gst_buffer_unmap(gst_output_buf, &map); +#endif + return GST_FLOW_OK; +} + + +void TizenVideoDecodeAccelerator::Impl::CreateAppSinkElement() { + GstAppSinkCallbacks appsink_callbacks = + { NULL, NULL, &OnDecoded }; + + if (!(sink_ = gst_element_factory_make("appsink", "sink"))) { + LOG(ERROR) << __FUNCTION__ << "Appsink could not be created"; + return; + } + gst_app_sink_set_callbacks(GST_APP_SINK(sink_), + &appsink_callbacks, + static_cast(this), + NULL); + gst_app_sink_set_max_buffers(GST_APP_SINK(sink_), 1); +} + +void TizenVideoDecodeAccelerator::Impl::DeliverVideoFrame( + GstBuffer* buffer, + int32 bitstream_buffer_id, + gfx::Rect frame_size) { + base::SharedMemory shared_memory; + base::SharedMemoryHandle shared_memory_handle; + +#if GST_VERSION_MAJOR == 1 + GstMapInfo map; + if (!gst_buffer_map(buffer, &map, GST_MAP_READ)) { + LOG (ERROR) << "Encoded Buffer contains invalid or no info.!"; + return; + } + uint32 buffer_size = map.size; +#else + uint32 buffer_size = buffer->size; +#endif + if (!shared_memory.CreateAndMapAnonymous(buffer_size)) { + LOG (ERROR) << "Shared Memory creation failed."; + } else { + if (!shared_memory.ShareToProcess(base::GetCurrentProcessHandle(), + &shared_memory_handle)) { + LOG(ERROR) << __FUNCTION__ << "Could not get handle of Shared Memory"; + } else { + memcpy(shared_memory.memory(), +#if GST_VERSION_MAJOR == 1 + map.data, +#else + GST_BUFFER_DATA(buffer), +#endif + buffer_size); + io_message_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&media::VideoDecodeAccelerator::Client::NotifyDecodeDone, + io_client_weak_factory_->GetWeakPtr(), + shared_memory_handle, + bitstream_buffer_id_, + buffer_size, + frame_size)); + } + } +#if GST_VERSION_MAJOR == 1 + gst_buffer_unmap(buffer, &map); +#endif + gst_buffer_unref(buffer); +} +#endif + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +void TizenVideoDecodeAccelerator::Impl::OnXWindowIdPrepared( + GstMessage* message) { +#if GST_VERSION_MAJOR == 1 + const GstStructure* structure = gst_message_get_structure(message); + gst_structure_get_int(structure, "video-width", &gst_width_); + gst_structure_get_int(structure, "video-height", &gst_height_); +#else + gst_structure_get_int(message->structure, "video-width", &gst_width_); + gst_structure_get_int(message->structure, "video-height", &gst_height_); +#endif + SetPixmap(gst_width_, gst_height_); + SetXWindowHandle(true); +} + +void TizenVideoDecodeAccelerator::Impl::SetXWindowHandle( + bool handle_set) { + is_x_window_handle_set_ = handle_set; +} + +void TizenVideoDecodeAccelerator::Impl::SetPixmap( + const int32& gst_width, const int32& gst_height) { + int32 key_wh = ConvertWidthAndHeightToKey(gst_width, gst_height); + PixmapSurfaceTizenMap::iterator it = xpixmap_buffer_map_.find(key_wh); + if (it != xpixmap_buffer_map_.end()) { + pixmap_surface_ = it->second; + pixmap_id_ = pixmap_surface_->GetId(); + } else { + pixmap_surface_ = + gfx::EflPixmap::Create(gfx::EflPixmapBase::UsageType::SURFACE, + gfx::Size(gst_width, gst_height)); + if (pixmap_surface_.get() == NULL) { + LOG(ERROR) << __FUNCTION__ << "Failed to create pixmap Surface"; + return; + } + pixmap_id_ = pixmap_surface_->GetId(); + xpixmap_buffer_map_[key_wh] = pixmap_surface_; + } + gst_width_ = gst_width; + gst_height_ = gst_height; + DeregisterDamageHandler(); + + // Register to get notification from ecore for damage updates. + damage_ = ecore_x_damage_new(pixmap_id_, + ECORE_X_DAMAGE_REPORT_RAW_RECTANGLES); + damage_handler_ = ecore_event_handler_add(ECORE_X_EVENT_DAMAGE_NOTIFY, + OnSurfaceChanged, + this); +#if GST_VERSION_MAJOR == 1 + gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(sink_), pixmap_id_); +#else + gst_x_overlay_set_window_handle(GST_X_OVERLAY(sink_), pixmap_id_); +#endif +} + +void TizenVideoDecodeAccelerator::Impl::DeregisterDamageHandler() { + if (damage_) { + ecore_x_damage_free(damage_); + damage_ = 0; + } + if (damage_handler_) { + ecore_event_handler_del(damage_handler_); + damage_handler_ = NULL; + } +} + +// Callback received when pixmap surface is changed/damaged +Eina_Bool TizenVideoDecodeAccelerator::Impl::OnSurfaceChanged(void* ptr_acc, + int type, + void* event) { + TizenVideoDecodeAccelerator::Impl* self = + static_cast(ptr_acc); + + if (self) { + media::Picture picture(self->pixmap_id_, + self->bitstream_buffer_id_, + gfx::Rect(self->gst_width_, self->gst_height_)); + + self->io_message_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&media::VideoDecodeAccelerator::Client::PictureReady, + self->io_client_weak_factory_->GetWeakPtr(), + picture) ); + self->bitstream_buffer_id_ = (self->bitstream_buffer_id_ + 1) & ID_LAST; + } else { + LOG(ERROR) << __FUNCTION__ << "Accelerator is NULL"; + return ECORE_CALLBACK_CANCEL; + } + return ECORE_CALLBACK_PASS_ON; +} + +void TizenVideoDecodeAccelerator::Impl::OnSinkCapChanged( + GstPad* sink_pad, GParamSpec* gparamspec,void* user_data) { + TizenVideoDecodeAccelerator::Impl* self = + static_cast(user_data); + if (!self) { + LOG(ERROR) << __FUNCTION__ << "Accelerator is NULL"; + return; + } + + int width = 0, height = 0; +#if GST_VERSION_MAJOR == 1 + GstCaps* caps = gst_pad_get_current_caps(GST_PAD(sink_pad)); + if (caps) { + GstVideoInfo info; + gst_video_info_init(&info); + + if (gst_video_info_from_caps(&info, caps)) { + width = info.width; + height = info.height; + if ((self->gst_width_ != width) || (self->gst_height_ != height)) { + self->SetPixmap(width, height); + } + } + } +#else + if (gst_video_get_size(sink_pad, &width, &height)) { + if ((self->gst_width_ != width) || (self->gst_height_ != height)) { + self->SetPixmap(width, height); + } + } +#endif +} +#endif + +void TizenVideoDecodeAccelerator::OnDecode( + scoped_ptr buffer_ref) { + if (!buffer_ref) { + return; + } +#if GST_VERSION_MAJOR == 1 + buffer_ref->gst_buffer_ = + gst_buffer_new_wrapped_full(GST_MEMORY_FLAG_READONLY, + static_cast(buffer_ref->shm_->memory()), + buffer_ref->size_, + 0, + buffer_ref->size_, + reinterpret_cast(buffer_ref.get()), + BitstreamBufferRef::Destruct); + if (!buffer_ref->gst_buffer_ || !GST_IS_BUFFER(buffer_ref->gst_buffer_)) { + LOG(ERROR) << " gst_buffer_new_wrapped_full failed to allocate memory.!"; + return; + } +#else + if (!(buffer_ref->gst_buffer_ = gst_buffer_new())) { + return; + } + + GST_BUFFER_MALLOCDATA(buffer_ref->gst_buffer_) = + reinterpret_cast(buffer_ref.get()); + GST_BUFFER_FREE_FUNC(buffer_ref->gst_buffer_) = BitstreamBufferRef::Destruct; + GST_BUFFER_SIZE(buffer_ref->gst_buffer_) = buffer_ref->size_; + GST_BUFFER_DATA(buffer_ref->gst_buffer_) = + static_cast(buffer_ref->shm_->memory()); +#endif + if (GST_FLOW_OK != + gst_app_src_push_buffer(GST_APP_SRC(impl_->appsrc_), + buffer_ref->gst_buffer_)) { + LOG(ERROR) << __FUNCTION__ << " fail to push buffer into decoder pipeline"; + return; + } + + // lifecycle of buffer_ref will be handled by gstreamer. + (void)buffer_ref.release(); +} + +void TizenVideoDecodeAccelerator::NotifyError( + media::VideoDecodeAccelerator::Error error) { + if (impl_->io_client_weak_factory_->GetWeakPtr()) { + impl_->io_client_weak_factory_->GetWeakPtr()->NotifyError(error); + } +} + +} // namespace content + diff --git a/tizen_src/chromium_impl/content/common/gpu/media/efl/tizen_video_decode_accelerator.h b/tizen_src/chromium_impl/content/common/gpu/media/efl/tizen_video_decode_accelerator.h new file mode 100644 index 000000000000..c312e5e589b4 --- /dev/null +++ b/tizen_src/chromium_impl/content/common/gpu/media/efl/tizen_video_decode_accelerator.h @@ -0,0 +1,53 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_COMMON_GPU_MEDIA_TIZEN_VIDEO_DECODE_ACCELERATOR_H_ +#define CONTENT_COMMON_GPU_MEDIA_TIZEN_VIDEO_DECODE_ACCELERATOR_H_ + +#include +#include +#include +#include +#include +#include + +#include "base/synchronization/lock.h" +#include "base/threading/thread.h" +#include "content/common/content_export.h" +#include "media/video/video_decode_accelerator.h" + +namespace content { + +class CONTENT_EXPORT TizenVideoDecodeAccelerator + : public media::VideoDecodeAccelerator { + public: + TizenVideoDecodeAccelerator(); + ~TizenVideoDecodeAccelerator() override; + + bool Initialize(media::VideoCodecProfile profile, Client* client) override; + void Decode(const media::BitstreamBuffer& bitstream_buffer) override; + void AssignPictureBuffers( + const std::vector& buffers) override; + void ReusePictureBuffer(int32 picture_buffer_id) override; + void Flush() override; + void Reset() override; + void Destroy() override; + bool CanDecodeOnIOThread() override; + + private: + struct BitstreamBufferRef; + struct Impl; + + void OnDecode(scoped_ptr buffer_ref); + void NotifyError(media::VideoDecodeAccelerator::Error error); + void StartDecoder(); + + Impl* impl_; + + DISALLOW_COPY_AND_ASSIGN(TizenVideoDecodeAccelerator); +}; + +} // namespace content + +#endif // CONTENT_COMMON_GPU_MEDIA_TIZEN_VIDEO_DECODE_ACCELERATOR_H_ diff --git a/tizen_src/chromium_impl/content/common/gpu/media/efl/tizen_video_encode_accelerator.cc b/tizen_src/chromium_impl/content/common/gpu/media/efl/tizen_video_encode_accelerator.cc new file mode 100644 index 000000000000..cd763295f167 --- /dev/null +++ b/tizen_src/chromium_impl/content/common/gpu/media/efl/tizen_video_encode_accelerator.cc @@ -0,0 +1,718 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/common/gpu/media/efl/tizen_video_encode_accelerator.h" + +#include +#include +#include +#include + +#include "base/bind.h" +#include "base/command_line.h" +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "base/timer/timer.h" +#include "gpu/command_buffer/service/gpu_switches.h" +#include "media/base/bitstream_buffer.h" +#include "third_party/webrtc/common_video/libyuv/include/webrtc_libyuv.h" + +using media::VideoFrame; + +namespace content { + +struct GstBufferDeleter { + inline void operator()(GstBuffer* ptr) const { + DCHECK(ptr != NULL); + gst_buffer_unref(ptr); + } +}; + +struct GstElementDeleter { + inline void operator()(GstElement* ptr) const { + DCHECK(ptr != NULL); + gst_object_unref(ptr); + } +}; + +enum { + // Arbitrary choice. + INITIAL_FRAMERATE = 30, + // Until there are non-realtime users, no need for unrequested I-frames. + INPUT_BUFFER_COUNT = 5, // default input buffer counts of omx_h264enc + MAX_BUFFERING = 60, + MAX_FRAME_RATE = 30, + // Max bitrate in bps + MAX_BITRATE = 2000000, + MAX_OUTPUT_BUFFERS = 30 // Maximum queue size of output buffers +}; +// Gstreamer elements and names. +const char* kEncoderName = "encoder"; +const char* kConvertorName = "cvt"; +#if GST_VERSION_MAJOR == 1 +const char* kEncoderGstElement = "omxh264enc"; +const char* kConvertorGstElement = "fimcconvert"; +#else +const char* kEncoderGstElement = "omx_h264enc"; +const char* kConvertorGstElement = "c2dconvert"; +#endif + + +media::VideoEncodeAccelerator* CreateTizenVideoEncodeAccelerator() { + return new TizenVideoEncodeAccelerator(); +} + +struct TizenVideoEncodeAccelerator::BitstreamBufferRef { + BitstreamBufferRef( + const scoped_refptr& frame, + base::WeakPtr client_delegate, + const scoped_refptr& client_message_loop_proxy, + size_t size) + : frame_(frame), + client_delegate_(client_delegate), + client_message_loop_proxy_(client_message_loop_proxy), + size_(size), + bytes_used_(0), + gst_buffer_(NULL) {} + + ~BitstreamBufferRef() {} + + static void Destruct(gpointer data) { + DCHECK(data != NULL); + BitstreamBufferRef* pRef = static_cast(data); + delete pRef; + } + + scoped_refptr frame_; + base::WeakPtr client_delegate_; + scoped_refptr client_message_loop_proxy_; + size_t size_; + off_t bytes_used_; + GstBuffer* gst_buffer_; +}; + +struct TizenVideoEncodeAccelerator::OutputBuffer { + explicit OutputBuffer( + GstBuffer* buffer, + bool key_frame) + : buffer_(buffer), + key_frame_(key_frame) {} + + virtual ~OutputBuffer() { + if(buffer_) + gst_buffer_unref(buffer_); + } + + GstBuffer* buffer_; + bool key_frame_; +}; + +struct TizenVideoEncodeAccelerator::Impl { + Impl(media::VideoEncodeAccelerator::Client* client, + scoped_refptr msg_loop) + : pipeline_(NULL), + encoder_(NULL), + appsrc_(NULL), + gst_thread_("GSTEncoder"), + enable_framedrop_(false), + io_client_weak_factory_(client), + child_message_loop_proxy_(msg_loop), + gst_bitrate_(0), + is_running_(false), + is_destroying_(false), + can_feed_(false) {} + + void DeliverVideoFrame(); + static GstFlowReturn OnEncoded(GstAppSink *sink,gpointer data); + static void StartFeed(GstAppSrc *source, guint size, gpointer data); + static void StopFeed(GstAppSrc *source, gpointer data); + + GstElement* pipeline_; + GstElement* encoder_; + GstElement* appsrc_; + base::Thread gst_thread_; + bool enable_framedrop_; + std::vector encoder_output_queue_; + base::WeakPtrFactory io_client_weak_factory_; + const scoped_refptr child_message_loop_proxy_; + base::Lock destroy_lock_; + base::ThreadChecker thread_checker_; + gfx::Size view_size_; + uint32 gst_bitrate_; + volatile bool is_running_; + volatile bool is_destroying_; + volatile bool can_feed_; + base::RepeatingTimer io_timer_; + std::queue output_buffers_; + base::Lock output_queue_lock_; +}; + +void TizenVideoEncodeAccelerator::Impl::DeliverVideoFrame() { + media::BitstreamBuffer* bs_buffer = NULL; + GstBuffer* buffer = NULL; + bool key_frame = false; + gsize gst_buffer_size = 0; +#if GST_VERSION_MAJOR == 1 + GstMapInfo map; +#endif + + scoped_ptr shm; + + if(output_buffers_.empty()) + return; + + if (encoder_output_queue_.empty()) { + // Observed till now that output_buffers_ size does not exceed 4-5. + // Therefore this code will be called in very rare situations. + if(output_buffers_.size() >= MAX_OUTPUT_BUFFERS) { + enable_framedrop_ = true; + TizenVideoEncodeAccelerator::OutputBuffer* drop_buffer = NULL; + { + base::AutoLock auto_lock(output_queue_lock_); + while(!output_buffers_.empty()) { + drop_buffer = output_buffers_.front(); + if (drop_buffer->key_frame_) + break; + output_buffers_.pop(); + gst_buffer_unref(drop_buffer->buffer_); + delete drop_buffer; + } + } + return; + } + return; + } + enable_framedrop_ = false; + key_frame = output_buffers_.front()->key_frame_; + bs_buffer = &encoder_output_queue_.back(); + encoder_output_queue_.pop_back(); + + shm.reset(new base::SharedMemory(bs_buffer->handle(), false)); + if (!shm->Map(bs_buffer->size())) { + LOG(ERROR) << "Failed to map SHM"; + io_client_weak_factory_.GetWeakPtr()->NotifyError( + media::VideoEncodeAccelerator::kPlatformFailureError); + gst_buffer_unref(buffer); + } + + { + base::AutoLock auto_lock(output_queue_lock_); + buffer = output_buffers_.front()->buffer_; + output_buffers_.pop(); + } +#if GST_VERSION_MAJOR == 1 + if (!gst_buffer_map(buffer, &map, GST_MAP_READ)) { + LOG (ERROR) << "Encoded Buffer contains invalid or no info.!"; + return; + } + gst_buffer_size = map.size; +#else + gst_buffer_size = buffer->size; +#endif + + + if (gst_buffer_size > shm->mapped_size()) { + LOG(ERROR) << "Encoded buff too large: " + << gst_buffer_size << ">" << shm->mapped_size(); + io_client_weak_factory_.GetWeakPtr()->NotifyError( + media::VideoEncodeAccelerator::kPlatformFailureError); + gst_buffer_unref(buffer); + } + //copying data to shared memory. +#if GST_VERSION_MAJOR == 1 + memcpy(static_cast(shm->memory()), map.data, gst_buffer_size); + gst_buffer_unmap(buffer, &map); +#else + memcpy(static_cast(shm->memory()), buffer->data, gst_buffer_size); +#endif + + child_message_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&media::VideoEncodeAccelerator::Client::BitstreamBufferReady, + io_client_weak_factory_.GetWeakPtr(), + bs_buffer->id(), + gst_buffer_size, + key_frame)); +} + +GstFlowReturn TizenVideoEncodeAccelerator::Impl::OnEncoded( + GstAppSink *sink, gpointer data) { + bool key_frame = false; + GstBuffer* gst_output_buf = NULL; + TizenVideoEncodeAccelerator::Impl* impl = + static_cast(data); +#if GST_VERSION_MAJOR == 1 + gst_output_buf = gst_sample_get_buffer(gst_app_sink_pull_sample(GST_APP_SINK(sink))); + GstMapInfo map; + if (!gst_buffer_map(gst_output_buf, &map, GST_MAP_READ)) + LOG (ERROR) << "Encoded Buffer contains invalid or no info!"; +#else + gst_output_buf = gst_app_sink_pull_buffer(GST_APP_SINK(sink)); +#endif + + if (gst_output_buf) { + if (!GST_BUFFER_FLAG_IS_SET(gst_output_buf, GST_BUFFER_FLAG_DELTA_UNIT)) { + key_frame = true; + } +#if GST_VERSION_MAJOR == 1 + if (map.data) { +#else + if (gst_output_buf->data) { +#endif + base::AutoLock auto_lock(impl->output_queue_lock_); + impl->output_buffers_.push( + new TizenVideoEncodeAccelerator::OutputBuffer(gst_output_buf, + key_frame)); + } + } else { + LOG(ERROR) << __FUNCTION__ << " ENCODING FRAME FAILED"; + } +#if GST_VERSION_MAJOR == 1 + gst_buffer_unmap(gst_output_buf, &map); +#endif + return GST_FLOW_OK; +} + +void TizenVideoEncodeAccelerator::Impl::StartFeed( + GstAppSrc *source, guint size, gpointer data) { + TizenVideoEncodeAccelerator::Impl* impl = + static_cast(data); + DCHECK(impl); + impl->can_feed_ = true; +} + +void TizenVideoEncodeAccelerator::Impl::StopFeed( + GstAppSrc *source, gpointer data) { + TizenVideoEncodeAccelerator::Impl* impl = + static_cast(data); + DCHECK(impl); + impl->can_feed_ = false; +} + +TizenVideoEncodeAccelerator::TizenVideoEncodeAccelerator() + : impl_(NULL) {} + +TizenVideoEncodeAccelerator::~TizenVideoEncodeAccelerator() {} + +std::vector +TizenVideoEncodeAccelerator::GetSupportedProfiles() { + std::vector profiles; + media::VideoEncodeAccelerator::SupportedProfile profile; + profile.profile = media::H264PROFILE_BASELINE; + profile.max_resolution.SetSize(1280, 720); + profile.max_framerate_numerator = 30; + profile.max_framerate_denominator = 1; + profiles.push_back(profile); + + return profiles; +} + +bool TizenVideoEncodeAccelerator::Initialize( + media::VideoFrame::Format input_format, + const gfx::Size& input_visible_size, + media::VideoCodecProfile output_profile, + uint32 initial_bitrate, + Client* client) { + DVLOG(1) << __FUNCTION__ + << " size :" << input_visible_size.ToString() + << " max bitrate :" << MAX_BITRATE << "bps"; + DCHECK(impl_ == NULL); + if (media::H264PROFILE_MIN > output_profile || + media::H264PROFILE_MAX < output_profile) { + NOTREACHED(); + return false; + } + + impl_ = new Impl(client, base::MessageLoopProxy::current()); + impl_->gst_bitrate_ = initial_bitrate; + impl_->view_size_ = input_visible_size; + impl_->gst_thread_.Start(); + + if (!StartEncoder()) { + delete impl_; + impl_ = NULL; + return false; + } + + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&media::VideoEncodeAccelerator::Client::RequireBitstreamBuffers, + impl_->io_client_weak_factory_.GetWeakPtr(), + (unsigned int)INPUT_BUFFER_COUNT, + input_visible_size, + MAX_BITRATE / 8)); // Maximum bytes for a frame by MAX_BITRATE. + return true; +} + +void TizenVideoEncodeAccelerator::Encode( + const scoped_refptr& frame, + bool force_keyframe) { + size_t frame_size = VideoFrame::AllocationSize(VideoFrame::I420, + frame->coded_size()); + DVLOG(3) << __FUNCTION__ + << " coded_size :" << frame->coded_size().ToString() + << " natural_size :" << frame->natural_size().ToString(); + + scoped_ptr buffer_ref; + + buffer_ref.reset( + new BitstreamBufferRef(frame, + impl_->io_client_weak_factory_.GetWeakPtr(), + impl_->child_message_loop_proxy_, + frame_size)); + + if (!buffer_ref) { + LOG(ERROR) << __FUNCTION__ << "malloc failed"; + return; + } + + if (impl_->can_feed_ && !impl_->is_destroying_) { + impl_->gst_thread_.message_loop()->PostTask( + FROM_HERE, + base::Bind(&TizenVideoEncodeAccelerator::OnEncode, + base::Unretained(this), + base::Passed(&buffer_ref), + force_keyframe)); + } else { + DVLOG(2) << __FUNCTION__ << " [WEBRTC] . FRAME DROP :" + << " can_feed_:" << impl_->can_feed_ + << " is_destroying_:" << impl_->is_destroying_; + } +} + +void TizenVideoEncodeAccelerator::UseOutputBitstreamBuffer( + const media::BitstreamBuffer& buffer) { + impl_->gst_thread_.message_loop()->PostTask( + FROM_HERE, + base::Bind(&TizenVideoEncodeAccelerator::OnUseOutputBitstreamBuffer, + base::Unretained(this), + buffer)); +} + +void TizenVideoEncodeAccelerator::RequestEncodingParametersChange( + uint32 bitrate, uint32 framerate) { + DVLOG(2) << __FUNCTION__ + << " bitrate: " << bitrate + << " framerate: " << framerate; + if (bitrate > 0 && bitrate != impl_->gst_bitrate_) { + impl_->gst_bitrate_ = bitrate; + // Omx Encoder expects bitrate in bps whereas ffenc expects bitrate in kbps + // Information can be gained by gst-inspect +#if defined(OS_TIZEN) + g_object_set(G_OBJECT(impl_->encoder_), +#if GST_VERSION_MAJOR == 1 + "target-bitrate", +#else + "bitrate", +#endif + std::min(bitrate, static_cast(MAX_BITRATE)), + NULL); +#else + g_object_set(G_OBJECT(impl_->encoder_), + "bitrate", + std::min(bitrate, static_cast(MAX_BITRATE)) / 1000, + NULL); +#endif + } +} + +void TizenVideoEncodeAccelerator::Destroy() { + if (impl_) { + DCHECK(impl_->thread_checker_.CalledOnValidThread()); + if(impl_->appsrc_) + gst_app_src_end_of_stream(GST_APP_SRC(impl_->appsrc_)); + + { + base::AutoLock auto_lock(impl_->destroy_lock_); + impl_->is_destroying_ = true; + } + + if (impl_->gst_thread_.IsRunning()) + impl_->gst_thread_.Stop(); + if (impl_->pipeline_) { + gst_element_set_state(impl_->pipeline_, GST_STATE_NULL); + gst_object_unref(GST_OBJECT(impl_->pipeline_)); + } + if (impl_->io_timer_.IsRunning()) + impl_->io_timer_.Stop(); + + while (!impl_->encoder_output_queue_.empty()) { + media::BitstreamBuffer bitstream_buffer = impl_->encoder_output_queue_.back(); + // created shm and let it go out of scope automatically. + scoped_ptr shm( + new base::SharedMemory(bitstream_buffer.handle(), false)); + impl_->encoder_output_queue_.pop_back(); + } + while (!impl_->output_buffers_.empty()) { + OutputBuffer* output_buffer = impl_->output_buffers_.front(); + gst_buffer_unref(output_buffer->buffer_); + impl_->output_buffers_.pop(); + } + delete impl_; + } + delete this; +} + +void TizenVideoEncodeAccelerator::OnEncode( + scoped_ptr buffer_ref, bool force_keyframe) { + + BitstreamBufferRef* bufref = buffer_ref.release(); + if (bufref == NULL) { + return; + } + +#if defined(OS_TIZEN) && GST_VERSION_MAJOR != 1 + g_object_set(impl_->encoder_, + "force-i-frame", + (force_keyframe || impl_->enable_framedrop_) ? TRUE : FALSE, + NULL); +#endif + +#if GST_VERSION_MAJOR == 1 + bufref->gst_buffer_ = + gst_buffer_new_wrapped_full(GST_MEMORY_FLAG_READONLY, + static_cast(bufref->frame_->data(VideoFrame::kYPlane)), + bufref->size_, + 0, + bufref->size_, + reinterpret_cast(bufref), + BitstreamBufferRef::Destruct); + if (!bufref->gst_buffer_ || !GST_IS_BUFFER(bufref->gst_buffer_)) { + LOG(INFO) << " gst_buffer_new_wrapped_full failed to allocate memory."; + return; + } +#else + if (!(bufref->gst_buffer_ = gst_buffer_new())) { + LOG(ERROR) << __FUNCTION__ << " gst_buffer_new failed to allocate memory.!"; + return; + } + + GST_BUFFER_MALLOCDATA(bufref->gst_buffer_) = reinterpret_cast(bufref); + GST_BUFFER_FREE_FUNC(bufref->gst_buffer_) = BitstreamBufferRef::Destruct; + GST_BUFFER_SIZE(bufref->gst_buffer_) = bufref->size_; + GST_BUFFER_DATA(bufref->gst_buffer_) = + static_cast(bufref->frame_->data(VideoFrame::kYPlane)); +#endif + if (GST_FLOW_OK != + gst_app_src_push_buffer(GST_APP_SRC(impl_->appsrc_), + bufref->gst_buffer_)) { + LOG(ERROR) << __FUNCTION__ + << " error while pushing buffer int appsrc on encoder."; + gst_buffer_unref(bufref->gst_buffer_); + } + + return; +} + +void TizenVideoEncodeAccelerator::OnUseOutputBitstreamBuffer( + const media::BitstreamBuffer& buffer) { + impl_->encoder_output_queue_.push_back(buffer); + + DVLOG(2) << __FUNCTION__ + << " output buffer is ready to use: " << buffer.id() + << " out queue size: " << impl_->encoder_output_queue_.size(); +} + +bool TizenVideoEncodeAccelerator::StartEncoder() { + GError* error = NULL; + GstCaps* appsrc_caps = NULL; + GstElement* gst_appsink = NULL; + scoped_ptr gst_pipeline; + + guint64 max_input_buffer = + INPUT_BUFFER_COUNT * VideoFrame::AllocationSize(VideoFrame::I420, + impl_->view_size_); + GstAppSrcCallbacks appsrc_callbacks = + { &TizenVideoEncodeAccelerator::Impl::StartFeed, + &TizenVideoEncodeAccelerator::Impl::StopFeed, + NULL }; + GstAppSinkCallbacks appsink_callbacks = + { NULL, NULL, &TizenVideoEncodeAccelerator::Impl::OnEncoded }; + + if (impl_->pipeline_ != NULL) { + return false; + } + + if (!gst_is_initialized() && !gst_init_check(NULL, NULL, &error)) { + LOG(ERROR) << __FUNCTION__ << " cannot initialize gstreamer."; + g_error_free(error); + return false; + } + + // pipeline initialization + gst_pipeline.reset(gst_pipeline_new("h264_encode")); + if (!gst_pipeline) { + LOG(ERROR) << __FUNCTION__ << " cannot initialize gst pipeline."; + return false; + } + + // appsrc initialization + if (!(impl_->appsrc_ = gst_element_factory_make ("appsrc", "src"))) { + LOG(ERROR) << __FUNCTION__ << "cannot initialize gst appsrc."; + return false; + } + if (!gst_bin_add(GST_BIN(gst_pipeline.get()), impl_->appsrc_)) { + LOG(ERROR) << __FUNCTION__ << " cannot add gst appsrc into encoder pipeline."; + gst_object_unref(impl_->appsrc_); + impl_->appsrc_ = NULL; + return false; + } + appsrc_caps = gst_caps_new_simple( +#if GST_VERSION_MAJOR == 1 + "video/x-raw", + "format", G_TYPE_STRING, gst_video_format_to_string(GST_VIDEO_FORMAT_I420), +#else + "video/x-raw-yuv", + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('I', '4', '2', '0'), +#endif + "width", G_TYPE_INT, impl_->view_size_.width(), + "height", G_TYPE_INT, impl_->view_size_.height(), + "framerate", GST_TYPE_FRACTION, 30, 1, + "rotate", G_TYPE_INT, 0, + NULL); + if (!appsrc_caps) { + LOG(ERROR) << __FUNCTION__ << " cannot create appsrc caps"; + return false; + } + gst_app_src_set_callbacks(GST_APP_SRC(impl_->appsrc_), &appsrc_callbacks, + static_cast(impl_), NULL); + gst_app_src_set_max_bytes(GST_APP_SRC(impl_->appsrc_), max_input_buffer); + gst_app_src_set_caps(GST_APP_SRC(impl_->appsrc_), appsrc_caps); + + // appsink initialization + if (!(gst_appsink = gst_element_factory_make("appsink", "sink"))) { + LOG(ERROR) << "cannot create appsink for encoder pipeline."; + return false; + } + if (!gst_bin_add(GST_BIN(gst_pipeline.get()), gst_appsink)) { + LOG(ERROR) << "cannot add gst appsink into encoder pipeline."; + gst_object_unref(gst_appsink); + return false; + } + gst_app_sink_set_callbacks(GST_APP_SINK(gst_appsink), &appsink_callbacks, + static_cast(impl_), NULL); + gst_app_sink_set_max_buffers(GST_APP_SINK(gst_appsink), 1); + +#ifdef OS_TIZEN + DVLOG(1) << "######################################"; + DVLOG(1) << " USING omx_h264enc ENCODER"; + DVLOG(1) << "######################################"; + + // encoder initialization + if (!(impl_->encoder_ = gst_element_factory_make(kEncoderGstElement, kEncoderName))) { + LOG(ERROR) << __FUNCTION__ << " cannot create " << kEncoderGstElement << "."; + return false; + } + if(!gst_bin_add(GST_BIN(gst_pipeline.get()), impl_->encoder_)) { + LOG(ERROR) << __FUNCTION__ << " cannot add omx_h264enc into encoder pipeline."; + gst_object_unref(impl_->encoder_); + impl_->encoder_ = NULL; + return false; + } + g_object_set(impl_->encoder_, + "control-rate", 2, // 1:VBR_CFR 2:CBR_CFR 3:VBR_VFR 4:CBR_VFR +#if GST_VERSION_MAJOR == 1 + "target-bitrate", impl_->gst_bitrate_, +#else + "encoder-profile", 1, // BASELINE_PROFILE + "byte-stream", TRUE, + "bitrate", impl_->gst_bitrate_, +#endif + NULL); + + g_object_set(G_OBJECT(impl_->appsrc_), + "is-live", TRUE, + "block", FALSE, + "do-timestamp", TRUE, + "min-latency", (gint64)(0), + "max-latency", (gint64)(0), + "min-percent", 80, // if buffer below 80%, need-data emits. + "stream-type", GST_APP_STREAM_TYPE_STREAM, + "format", GST_FORMAT_DEFAULT, + NULL); + + g_object_set(gst_appsink, "sync", FALSE, NULL); + + if (!gst_element_link(impl_->appsrc_, impl_->encoder_)) { + LOG(ERROR) << " cannot link impl_->appsrc_ with encoder_."; + return false; + } + + if (!gst_element_link(impl_->encoder_, gst_appsink)) { + LOG(ERROR) << " cannot link encoder_ to sink."; + return false; + } +#else + DVLOG(1) << "######################################"; + DVLOG(1) << " USING x264enc ENCODER"; + DVLOG(1) << "######################################"; + GstElement* gst_parser = NULL; + + // parser initialization + if (!(gst_parser = gst_element_factory_make("videoparse", "parse"))) { + LOG(ERROR) << __FUNCTION__ << " cannot create videoparse."; + return false; + } + if(!gst_bin_add(GST_BIN(gst_pipeline.get()), gst_parser)) { + LOG(ERROR) << __FUNCTION__ << " cannot add videoparse into encoder pipeline."; + gst_object_unref(gst_parser); + return false; + } + g_object_set(gst_parser, + "format", GST_VIDEO_FORMAT_I420, + "width", impl_->view_size_.width(), + "height", impl_->view_size_.height(), + "framerate", INITIAL_FRAMERATE, 1, + NULL); + + if (!(impl_->encoder_ = gst_element_factory_make ("x264enc","encoder"))) { + LOG(ERROR) << __FUNCTION__ << " cannot create x264enc encoder."; + return false; + } + if(!gst_bin_add(GST_BIN(gst_pipeline.get()), impl_->encoder_)) { + LOG(ERROR) << __FUNCTION__ << " cannot add x264enc into encoder pipeline."; + gst_object_unref(impl_->encoder_); + return false; + } + g_object_set(impl_->encoder_, + "byte-stream", TRUE, + "bitrate", impl_->gst_bitrate_, + "tune",0x00000004,"profile", 1, NULL); + + g_object_set(G_OBJECT(impl_->appsrc_), + "is-live", TRUE, + "block", FALSE, + "do-timestamp", TRUE, + "stream-type", 0, + "min-latency", (gint64)(0), + "max-latency", (gint64)(0), + "format", GST_FORMAT_TIME, + NULL); + + g_object_set(gst_appsink, "sync", FALSE, NULL); + + if (!gst_element_link_many(impl_->appsrc_, gst_parser, + impl_->encoder_, gst_appsink, NULL)) { + LOG(ERROR) << __FUNCTION__ << " cannot link for encoder pipeline."; + return false; + } +#endif + + if (GST_STATE_CHANGE_FAILURE == + gst_element_set_state(gst_pipeline.get(), GST_STATE_PLAYING)) { + LOG(ERROR) << __FUNCTION__ << " cannot start encoder pipeline."; + return false; + } + impl_->io_timer_.Start(FROM_HERE, + base::TimeDelta::FromMilliseconds(10), + impl_, + &TizenVideoEncodeAccelerator::Impl::DeliverVideoFrame); + GST_DEBUG_BIN_TO_DOT_FILE( + GST_BIN(gst_pipeline.get()), GST_DEBUG_GRAPH_SHOW_ALL, "encoder_graph.dot"); + + impl_->pipeline_ = gst_pipeline.release(); + return true; +} + +} // namespace content diff --git a/tizen_src/chromium_impl/content/common/gpu/media/efl/tizen_video_encode_accelerator.h b/tizen_src/chromium_impl/content/common/gpu/media/efl/tizen_video_encode_accelerator.h new file mode 100644 index 000000000000..08218807775a --- /dev/null +++ b/tizen_src/chromium_impl/content/common/gpu/media/efl/tizen_video_encode_accelerator.h @@ -0,0 +1,52 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_COMMON_GPU_MEDIA_TIZEN_VIDEO_ENCODE_ACCELERATOR_H_ +#define CONTENT_COMMON_GPU_MEDIA_TIZEN_VIDEO_ENCODE_ACCELERATOR_H_ + +#include "base/threading/thread.h" +#include "base/synchronization/lock.h" +#include "base/synchronization/waitable_event.h" +#include "content/common/content_export.h" +#include "media/video/video_encode_accelerator.h" + +namespace content { + +class CONTENT_EXPORT TizenVideoEncodeAccelerator + : public media::VideoEncodeAccelerator { + public: + TizenVideoEncodeAccelerator(); + ~TizenVideoEncodeAccelerator() override; + + std::vector + GetSupportedProfiles() override; + bool Initialize(media::VideoFrame::Format input_format, + const gfx::Size& input_visible_size, + media::VideoCodecProfile output_profile, + uint32 initial_bitrate, + Client* client) override; + void Encode(const scoped_refptr& frame, + bool force_keyframe) override; + void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer) override; + void RequestEncodingParametersChange(uint32 bitrate, + uint32 framerate) override; + void Destroy() override; + + private: + struct BitstreamBufferRef; + struct Impl; + struct OutputBuffer; + + void OnEncode(scoped_ptr buffer_ref, bool force_keyframe); + void OnUseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer); + bool StartEncoder(); + + Impl* impl_; + + DISALLOW_COPY_AND_ASSIGN(TizenVideoEncodeAccelerator); +}; + +} // namespace content + +#endif // CONTENT_COMMON_GPU_MEDIA_TIZEN_VIDEO_ENCODE_ACCELERATOR_TIZEN_H_ diff --git a/tizen_src/chromium_impl/content/common/media/efl/media_player_messages_efl.h b/tizen_src/chromium_impl/content/common/media/efl/media_player_messages_efl.h new file mode 100644 index 000000000000..02fc757572d7 --- /dev/null +++ b/tizen_src/chromium_impl/content/common/media/efl/media_player_messages_efl.h @@ -0,0 +1,200 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// IPC messages for tizen media player. +// Multiply-included message file, hence no include guard. + +#include "content/common/content_export.h" +#include "ipc/ipc_message_macros.h" +#include "media/base/media_keys.h" +#include "media/base/efl/demuxer_stream_player_params_efl.h" +#include "media/base/efl/media_player_manager_efl.h" +#include "ui/gfx/rect_f.h" + +#undef IPC_MESSAGE_EXPORT +#define IPC_MESSAGE_EXPORT CONTENT_EXPORT +#define IPC_MESSAGE_START MediaPlayerEflMsgStart + +IPC_ENUM_TRAITS(media::AudioCodec) +IPC_ENUM_TRAITS(media::MediaPlayerEfl::ReadyState) +IPC_ENUM_TRAITS(media::MediaPlayerEfl::NetworkState) +IPC_ENUM_TRAITS(media::DemuxerStream::Status) +IPC_ENUM_TRAITS(media::DemuxerStream::Type) +IPC_ENUM_TRAITS(media::VideoCodec) +IPC_ENUM_TRAITS(MediaPlayerHostMsg_Initialize_Type) + +IPC_STRUCT_TRAITS_BEGIN(media::DemuxerConfigs) + IPC_STRUCT_TRAITS_MEMBER(audio_codec) + IPC_STRUCT_TRAITS_MEMBER(audio_channels) + IPC_STRUCT_TRAITS_MEMBER(audio_sampling_rate) + IPC_STRUCT_TRAITS_MEMBER(is_audio_encrypted) + IPC_STRUCT_TRAITS_MEMBER(audio_extra_data) + + IPC_STRUCT_TRAITS_MEMBER(video_codec) + IPC_STRUCT_TRAITS_MEMBER(video_size) + IPC_STRUCT_TRAITS_MEMBER(is_video_encrypted) + IPC_STRUCT_TRAITS_MEMBER(video_extra_data) + + IPC_STRUCT_TRAITS_MEMBER(duration_ms) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(media::DemuxedBufferMetaData) + IPC_STRUCT_TRAITS_MEMBER(size) + IPC_STRUCT_TRAITS_MEMBER(end_of_stream) + IPC_STRUCT_TRAITS_MEMBER(timestamp) + IPC_STRUCT_TRAITS_MEMBER(time_duration) + IPC_STRUCT_TRAITS_MEMBER(type) + IPC_STRUCT_TRAITS_MEMBER(status) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(media::SubsampleEntry) + IPC_STRUCT_TRAITS_MEMBER(clear_bytes) + IPC_STRUCT_TRAITS_MEMBER(cypher_bytes) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(media::MediaPlayerEfl::TimeRanges) + IPC_STRUCT_TRAITS_MEMBER(start) + IPC_STRUCT_TRAITS_MEMBER(end) +IPC_STRUCT_TRAITS_END() + +// Initialize Gst player. +IPC_MESSAGE_ROUTED5(MediaPlayerGstHostMsg_Init, + int /* player_id */, + MediaPlayerHostMsg_Initialize_Type /* type */, + GURL /* URL */, + double /* volume */, + int /* demuxer client id */) + +// Deinitialize Gst player. +IPC_MESSAGE_ROUTED1(MediaPlayerGstHostMsg_DeInit, + int /* player_id */) + +// Start playback. +IPC_MESSAGE_ROUTED1(MediaPlayerGstHostMsg_Play, + int /* player_id */) + +// Pause playback. +IPC_MESSAGE_ROUTED1(MediaPlayerGstHostMsg_Pause, + int /* player_id */) + +// Set volume. +IPC_MESSAGE_ROUTED2(MediaPlayerGstHostMsg_SetVolume, + int /* player_id */, + double /* volume */) + +// Set playback rate. +IPC_MESSAGE_ROUTED2(MediaPlayerGstHostMsg_SetRate, + int /* player_id */, + double /* rate */) + +// Playback duration. +IPC_MESSAGE_ROUTED2(MediaPlayerGstMsg_DurationChanged, + int /* player_id */, + double /* time */) + +// Current duration. +IPC_MESSAGE_ROUTED2(MediaPlayerGstMsg_TimeUpdate, + int /* player_id */, + double /* time */) + +// Pause state. +IPC_MESSAGE_ROUTED2(MediaPlayerGstMsg_OnPauseStateChange, + int /* player_id */, + bool /* state */) + +// Seek state. +IPC_MESSAGE_ROUTED2(MediaPlayerGstMsg_OnSeekStateChange, + int /* player_id */, + bool /* state */) + +// Current buffer range. +IPC_MESSAGE_ROUTED2(MediaPlayerGstMsg_BufferUpdate, + int /* player_id */, + std::vector /*buffer_range*/) + +// Playback completed. +IPC_MESSAGE_ROUTED1(MediaPlayerGstMsg_TimeChanged, + int /* player_id */) + +// Ready state change. +IPC_MESSAGE_ROUTED2(MediaPlayerGstMsg_ReadyStateChange, + int /* player_id */, + media::MediaPlayerEfl::ReadyState /* state */) + +// Network state change. +IPC_MESSAGE_ROUTED2(MediaPlayerGstMsg_NetworkStateChange, + int /* player_id */, + media::MediaPlayerEfl::NetworkState /* state */) + +// Gst media data has changed. +IPC_MESSAGE_ROUTED5(MediaPlayerGstMsg_MediaDataChanged, + int /* player_id */, + int /* format */, + int /* height */, + int /* width */, + int /* media */) + +// On new frame available. +IPC_MESSAGE_ROUTED4(MediaPlayerGstMsg_NewFrameAvailable, + int /* player_id */, + base::SharedMemoryHandle /* Handle */, + uint32 /* length */, + base::TimeDelta /* time stamp */) + +#ifdef OS_TIZEN +IPC_MESSAGE_ROUTED3(MediaPlayerGstMsg_PlatformSurfaceUpdated, + int /* player_id */, + int /* pixmap_id */, + base::TimeDelta /* time stamp */) +#endif + +// Seek. +IPC_MESSAGE_ROUTED2(MediaPlayerGstHostMsg_Seek, + int /* player_id */, + double /* time */) + +// For MSE internal seek request. +IPC_MESSAGE_ROUTED2(MediaPlayerGstMsg_SeekRequest, + int /* player_id */, + double /* time_to_seek */) + +// Sent after the renderer demuxer has seeked. +IPC_MESSAGE_CONTROL2(MediaPlayerGstHostMsg_DemuxerSeekDone, + int /* demuxer_client_id */, + base::TimeDelta /* actual_browser_seek_time */) + +// Inform the media source player that the demuxer is ready. +IPC_MESSAGE_CONTROL2(MediaPlayerGstHostMsg_DemuxerReady, + int /* demuxer_client_id */, + media::DemuxerConfigs /* configs */) + +// Sent when the data was read from the ChunkDemuxer. +IPC_MESSAGE_CONTROL3(MediaPlayerGstHostMsg_ReadFromDemuxerAck, + int /* demuxer_client_id */, + base::SharedMemoryHandle /* Handle */, + media::DemuxedBufferMetaData /* meta data of buffer*/) + +// Sent when the data was read from the ChunkDemuxer. +IPC_MESSAGE_CONTROL2(MediaPlayerGstHostMsg_BufferMetaDataAck, + int /* demuxer_client_id */, + media::DemuxedBufferMetaData /* meta data of buffer*/) + +// Inform the media source player of changed media duration from demuxer. +IPC_MESSAGE_CONTROL2(MediaPlayerGstHostMsg_DurationChanged, + int /* demuxer_client_id */, + base::TimeDelta /* duration */) + +// The player needs new config data +IPC_MESSAGE_CONTROL1(MediaPlayerGstMsg_MediaConfigRequest, + int /* demuxer_client_id */) + +// The media source player reads data from demuxer +IPC_MESSAGE_CONTROL2(MediaPlayerGstMsg_ReadFromDemuxer, + int /* demuxer_client_id */, + media::DemuxerStream::Type /* type */) + +// Requests renderer demuxer seek. +IPC_MESSAGE_CONTROL2(MediaPlayerGstMsg_DemuxerSeekRequest, + int /* demuxer_client_id */, + base::TimeDelta /* time_to_seek */) diff --git a/tizen_src/chromium_impl/content/common/media/efl/media_player_messages_enums_efl.h b/tizen_src/chromium_impl/content/common/media/efl/media_player_messages_enums_efl.h new file mode 100644 index 000000000000..efb770160e77 --- /dev/null +++ b/tizen_src/chromium_impl/content/common/media/efl/media_player_messages_enums_efl.h @@ -0,0 +1,14 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_COMMON_MEDIA_MEDIA_PLAYER_MESSAGES_ENUMS_EFL_H_ +#define CONTENT_COMMON_MEDIA_MEDIA_PLAYER_MESSAGES_ENUMS_EFL_H_ + +// Dictates which type of media playback is being initialized. +enum MediaPlayerHostMsg_Initialize_Type { + MEDIA_PLAYER_TYPE_URL, + MEDIA_PLAYER_TYPE_MEDIA_SOURCE, +}; + +#endif // CONTENT_COMMON_MEDIA_MEDIA_PLAYER_MESSAGES_ENUMS_EFL_H_ diff --git a/tizen_src/chromium_impl/content/common/message_generator_efl.cc b/tizen_src/chromium_impl/content/common/message_generator_efl.cc new file mode 100644 index 000000000000..570a9fbefb11 --- /dev/null +++ b/tizen_src/chromium_impl/content/common/message_generator_efl.cc @@ -0,0 +1,33 @@ +// Copyright 2014 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Get basic type definitions. +#define IPC_MESSAGE_IMPL +#include "content/common/message_generator_efl.h" + +// Generate constructors. +#include "ipc/struct_constructor_macros.h" +#include "content/common/message_generator_efl.h" + +// Generate destructors. +#include "ipc/struct_destructor_macros.h" +#include "content/common/message_generator_efl.h" + +// Generate param traits write methods. +#include "ipc/param_traits_write_macros.h" +namespace IPC { +#include "content/common/message_generator_efl.h" +} // namespace IPC + +// Generate param traits read methods. +#include "ipc/param_traits_read_macros.h" +namespace IPC { +#include "content/common/message_generator_efl.h" +} // namespace IPC + +// Generate param traits log methods. +#include "ipc/param_traits_log_macros.h" +namespace IPC { +#include "content/common/message_generator_efl.h" +} // namespace IPC diff --git a/tizen_src/chromium_impl/content/common/message_generator_efl.h b/tizen_src/chromium_impl/content/common/message_generator_efl.h new file mode 100644 index 000000000000..3a03df0c2f3e --- /dev/null +++ b/tizen_src/chromium_impl/content/common/message_generator_efl.h @@ -0,0 +1,14 @@ +// Copyright 2014 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Multiply-included file, hence no include guard. +// efl message generator + +#include "content/common/render_messages_efl.h" +#if !defined(EWK_BRINGUP) +#include "components/editing/content/common/editing_messages.h" +#endif +#if defined(OS_TIZEN_MOBILE) +#include "content/common/tts_messages_efl.h" +#endif diff --git a/tizen_src/chromium_impl/content/common/navigation_policy_params.cc b/tizen_src/chromium_impl/content/common/navigation_policy_params.cc new file mode 100644 index 000000000000..461cc24fce65 --- /dev/null +++ b/tizen_src/chromium_impl/content/common/navigation_policy_params.cc @@ -0,0 +1,23 @@ +// Copyright 2014 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/common/navigation_policy_params.h" + +#include "third_party/WebKit/public/web/WebNavigationPolicy.h" + +namespace content { + +NavigationPolicyParams::NavigationPolicyParams() + : render_view_id(-1) + , policy(blink::WebNavigationPolicyIgnore) + , type(blink::WebNavigationTypeOther) + , should_replace_current_entry(false) + , is_main_frame(false) + , is_redirect(false) { +} + +NavigationPolicyParams::~NavigationPolicyParams() { +} + +} // namespace content diff --git a/tizen_src/chromium_impl/content/common/navigation_policy_params.h b/tizen_src/chromium_impl/content/common/navigation_policy_params.h new file mode 100644 index 000000000000..97aecc9bbfc3 --- /dev/null +++ b/tizen_src/chromium_impl/content/common/navigation_policy_params.h @@ -0,0 +1,35 @@ +// Copyright 2014 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef POLICY_NAVIGATION_PARAMS_H_ +#define POLICY_NAVIGATION_PARAMS_H_ + +#include "content/public/common/referrer.h" +#include "third_party/WebKit/public/web/WebNavigationPolicy.h" +#include "third_party/WebKit/public/web/WebNavigationType.h" +#include "third_party/WebKit/public/platform/WebString.h" +#include "url/gurl.h" + +namespace content { + +struct NavigationPolicyParams { + NavigationPolicyParams(); + ~NavigationPolicyParams(); + + int render_view_id; + GURL url; + std::string httpMethod; + content::Referrer referrer; + blink::WebNavigationPolicy policy; + blink::WebNavigationType type; + blink::WebString auth; + std::string cookie; + bool should_replace_current_entry; + bool is_main_frame; + bool is_redirect; +}; + +} // namespace content + +#endif /* POLICY_NAVIGATION_PARAMS_H_ */ diff --git a/tizen_src/chromium_impl/content/common/render_messages_efl.h b/tizen_src/chromium_impl/content/common/render_messages_efl.h new file mode 100644 index 000000000000..0de863343686 --- /dev/null +++ b/tizen_src/chromium_impl/content/common/render_messages_efl.h @@ -0,0 +1,354 @@ +// Copyright 2014 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Multiply-included file, no traditional include guard. + +#include "base/values.h" +#include "ipc/ipc_message_macros.h" +#include "ipc/ipc_channel_handle.h" +#include "content/common/cache_params_efl.h" +#include "content/common/navigation_policy_params.h" +#include "content/public/common/common_param_traits.h" +#include "content/public/common/referrer.h" +#include "content/renderer/print_pages_params.h" +#include "ui/gfx/ipc/gfx_param_traits.h" +#if !defined(EWK_BRINGUP) +#include "API/ewk_hit_test_private.h" +#include "API/ewk_text_style_private.h" +#endif // !EWK_BRINGUP +#include "third_party/WebKit/public/web/WebNavigationPolicy.h" +#include "third_party/WebKit/public/web/WebNavigationType.h" +#include "third_party/WebKit/public/web/WebViewModeEnums.h" +#include "ui/gfx/ipc/gfx_param_traits.h" +#include "url/gurl.h" + +#if !defined(EWK_BRINGUP) +#include "tizen_webview/public/tw_content_security_policy.h" +#include "tizen_webview/public/tw_error.h" +#include "tizen_webview/public/tw_hit_test.h" +#include "tizen_webview/public/tw_settings.h" +#include "tizen_webview/public/tw_wrt.h" +#endif // !EWK_BRINGUP + +#include +#include + +#if defined(TIZEN_MULTIMEDIA_SUPPORT) +#include "base/file_descriptor_posix.h" +#include "base/memory/shared_memory.h" +#endif + +typedef std::map StringMap; + +//----------------------------------------------------------------------------- +// RenderView messages +// These are messages sent from the browser to the renderer process. + +// these messages belong to "chrome messages" in chromium +// we can add our own class for them but then we need to patch ipc/ipc_message_start.h +// so using same message class for these messages. +// but actual messages are different so they shouldn't mess with chrome messages +#define IPC_MESSAGE_START ChromeMsgStart + +IPC_STRUCT_TRAITS_BEGIN(CacheParamsEfl) + IPC_STRUCT_TRAITS_MEMBER(cache_total_capacity) + IPC_STRUCT_TRAITS_MEMBER(cache_min_dead_capacity) + IPC_STRUCT_TRAITS_MEMBER(cache_max_dead_capacity) +IPC_STRUCT_TRAITS_END() + +#if !defined(EWK_BRINGUP) +IPC_ENUM_TRAITS(tizen_webview::ContentSecurityPolicyType) +#endif + +IPC_ENUM_TRAITS(blink::WebNavigationPolicy) +IPC_ENUM_TRAITS(blink::WebNavigationType) + +IPC_STRUCT_TRAITS_BEGIN(content::NavigationPolicyParams) + IPC_STRUCT_TRAITS_MEMBER(render_view_id) + IPC_STRUCT_TRAITS_MEMBER(cookie) + IPC_STRUCT_TRAITS_MEMBER(url) + IPC_STRUCT_TRAITS_MEMBER(httpMethod) + IPC_STRUCT_TRAITS_MEMBER(referrer) + IPC_STRUCT_TRAITS_MEMBER(policy) + IPC_STRUCT_TRAITS_MEMBER(type) + IPC_STRUCT_TRAITS_MEMBER(should_replace_current_entry) + IPC_STRUCT_TRAITS_MEMBER(is_main_frame) + IPC_STRUCT_TRAITS_MEMBER(is_redirect) +IPC_STRUCT_TRAITS_END() + +#if !defined(EWK_BRINGUP) +IPC_STRUCT_TRAITS_BEGIN(SelectionColor) + IPC_STRUCT_TRAITS_MEMBER(r) + IPC_STRUCT_TRAITS_MEMBER(g) + IPC_STRUCT_TRAITS_MEMBER(b) + IPC_STRUCT_TRAITS_MEMBER(a) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(SelectionStylePrams) + IPC_STRUCT_TRAITS_MEMBER(underline_state) + IPC_STRUCT_TRAITS_MEMBER(italic_state) + IPC_STRUCT_TRAITS_MEMBER(bold_state) + IPC_STRUCT_TRAITS_MEMBER(bg_color) + IPC_STRUCT_TRAITS_MEMBER(color) + IPC_STRUCT_TRAITS_MEMBER(font_size) + IPC_STRUCT_TRAITS_MEMBER(order_list_state) + IPC_STRUCT_TRAITS_MEMBER(un_order_list_state) + IPC_STRUCT_TRAITS_MEMBER(text_align_center_state) + IPC_STRUCT_TRAITS_MEMBER(text_align_left_state) + IPC_STRUCT_TRAITS_MEMBER(text_align_right_state) + IPC_STRUCT_TRAITS_MEMBER(text_align_full_state) + IPC_STRUCT_TRAITS_MEMBER(has_composition) +IPC_STRUCT_TRAITS_END() + +IPC_ENUM_TRAITS(tizen_webview::Hit_Test_Mode) +IPC_ENUM_TRAITS(tizen_webview::Hit_Test_Result_Context) + +IPC_STRUCT_TRAITS_BEGIN(_Ewk_Hit_Test::Hit_Test_Node_Data) + IPC_STRUCT_TRAITS_MEMBER(tagName) + IPC_STRUCT_TRAITS_MEMBER(nodeValue) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(_Ewk_Hit_Test::Hit_Test_Image_Buffer) + IPC_STRUCT_TRAITS_MEMBER(fileNameExtension) + IPC_STRUCT_TRAITS_MEMBER(imageBitmap) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(_Ewk_Hit_Test) + IPC_STRUCT_TRAITS_MEMBER(context) + IPC_STRUCT_TRAITS_MEMBER(linkURI) + IPC_STRUCT_TRAITS_MEMBER(linkLabel) + IPC_STRUCT_TRAITS_MEMBER(linkTitle) + IPC_STRUCT_TRAITS_MEMBER(imageURI) + IPC_STRUCT_TRAITS_MEMBER(mediaURI) + IPC_STRUCT_TRAITS_MEMBER(isEditable) + IPC_STRUCT_TRAITS_MEMBER(mode) + IPC_STRUCT_TRAITS_MEMBER(nodeData) +// XXX: find a better way to prevent the crash when copying SkBitmap +#if !defined(EWK_BRINGUP) + IPC_STRUCT_TRAITS_MEMBER(imageData) +#endif +IPC_STRUCT_TRAITS_END() +#endif + +IPC_STRUCT_TRAITS_BEGIN(content::DidPrintPagesParams) + IPC_STRUCT_TRAITS_MEMBER(metafile_data_handle) + IPC_STRUCT_TRAITS_MEMBER(data_size) + IPC_STRUCT_TRAITS_MEMBER(document_cookie) + IPC_STRUCT_TRAITS_MEMBER(filename) +IPC_STRUCT_TRAITS_END() + +#if !defined(EWK_BRINGUP) +IPC_STRUCT_TRAITS_BEGIN(tizen_webview::WrtIpcMessageData) + IPC_STRUCT_TRAITS_MEMBER(type) + IPC_STRUCT_TRAITS_MEMBER(value) + IPC_STRUCT_TRAITS_MEMBER(id) + IPC_STRUCT_TRAITS_MEMBER(reference_id) +IPC_STRUCT_TRAITS_END() +#endif + +IPC_ENUM_TRAITS(blink::WebViewMode) + +#if !defined(EWK_BRINGUP) +IPC_STRUCT_TRAITS_BEGIN(tizen_webview::Settings) + IPC_STRUCT_TRAITS_MEMBER(javascript_can_open_windows) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(tizen_webview::Error) + IPC_STRUCT_TRAITS_MEMBER(url) + IPC_STRUCT_TRAITS_MEMBER(is_main_frame) + IPC_STRUCT_TRAITS_MEMBER(code) + IPC_STRUCT_TRAITS_MEMBER(description) + IPC_STRUCT_TRAITS_MEMBER(domain) +IPC_STRUCT_TRAITS_END() +#endif + +// Tells the renderer to clear the cache. +IPC_MESSAGE_CONTROL0(EflViewMsg_ClearCache) +IPC_MESSAGE_ROUTED0(EwkViewMsg_UseSettingsFont) +IPC_MESSAGE_ROUTED0(EwkViewMsg_SetBrowserFont) +IPC_MESSAGE_ROUTED0(EwkViewMsg_SuspendScheduledTask) +IPC_MESSAGE_ROUTED0(EwkViewMsg_ResumeScheduledTasks) +IPC_MESSAGE_CONTROL1(EflViewMsg_SetCache, + CacheParamsEfl) + +// Tells the renderer to dump as much memory as it can, perhaps because we +// have memory pressure or the renderer is (or will be) paged out. This +// should only result in purging objects we can recalculate, e.g. caches or +// JS garbage, not in purging irreplaceable objects. +IPC_MESSAGE_CONTROL0(EwkViewMsg_PurgeMemory) + +IPC_MESSAGE_CONTROL4(WrtMsg_SetWidgetInfo, + int, // result: widgetHandle + double, // result: scale + std::string, // result: theme + std::string) // result: encodedBundle + +IPC_MESSAGE_CONTROL2(WrtMsg_ParseUrl, + int, // result: request_id + GURL) // result: url + +IPC_MESSAGE_CONTROL2(WrtMsg_ParseUrlResponse, + int, // result: request_id + GURL) // result: url + +#if !defined(EWK_BRINGUP) +IPC_MESSAGE_CONTROL1(WrtMsg_SendWrtMessage, + tizen_webview::WrtIpcMessageData /* data */); +#endif + +IPC_MESSAGE_ROUTED0(EwkViewMsg_GetSelectionStyle) + +#if !defined(EWK_BRINGUP) +IPC_MESSAGE_ROUTED2(EwkViewMsg_SetCSP, + std::string, /* policy */ + tizen_webview::ContentSecurityPolicyType /* header type */) +#endif + +IPC_MESSAGE_ROUTED2(EwkViewMsg_SetScroll, + int, /* horizontal position */ + int /* vertical position */) + +#if !defined(EWK_BRINGUP) +IPC_MESSAGE_ROUTED3(EwkViewMsg_DoHitTest, + int, /* horizontal position */ + int, /* vertical position */ + tizen_webview::Hit_Test_Mode /* mode */) + +IPC_MESSAGE_ROUTED4(EwkViewMsg_DoHitTestAsync, + int, /* horizontal position */ + int, /* vertical position */ + tizen_webview::Hit_Test_Mode, /* mode */ + int64_t /* request id */) + +IPC_MESSAGE_ROUTED1(EwkViewMsg_DidFailLoadWithError, + tizen_webview::Error /* error */) +#endif + +IPC_MESSAGE_ROUTED3(EwkViewMsg_PrintToPdf, + int, /* width */ + int, /* height */ + base::FilePath /* file name to save pdf*/) + +#if !defined(EWK_BRINGUP) +IPC_MESSAGE_ROUTED1(EflViewMsg_UpdateSettings, tizen_webview::Settings) +#endif + +// from renderer to browser + +IPC_MESSAGE_ROUTED1(EwkHostMsg_DidPrintPagesToPdf, + content::DidPrintPagesParams /* pdf document parameters */) + +IPC_SYNC_MESSAGE_CONTROL1_1(EwkHostMsg_DecideNavigationPolicy, + content::NavigationPolicyParams, + bool /*handled*/) + +#if !defined(EWK_BRINGUP) +IPC_SYNC_MESSAGE_ROUTED0_2(EwkHostMsg_GetContentSecurityPolicy, + std::string, /* policy */ + tizen_webview::ContentSecurityPolicyType /* header type */) + +IPC_SYNC_MESSAGE_ROUTED1_1(EwkHostMsg_WrtSyncMessage, + tizen_webview::WrtIpcMessageData /* data */, + std::string /*result*/); +#endif + +IPC_MESSAGE_ROUTED3(EwkViewMsg_Scale, + double, /* scale factor */ + int, /* center x */ + int /* center y */) + +IPC_MESSAGE_ROUTED1(EwkViewMsg_PlainTextGet, + int /* callback id */) + +IPC_MESSAGE_ROUTED2(EwkHostMsg_PlainTextGetContents, + std::string, /* contentText */ + int /* callback id */) + +#if !defined(EWK_BRINGUP) +IPC_MESSAGE_ROUTED1(EwkHostMsg_WrtMessage, + tizen_webview::WrtIpcMessageData /* data */); +#endif + +IPC_MESSAGE_ROUTED2(EwkHostMsg_DidChangeContentsSize, + int, /* width */ + int /* height */) + +#if !defined(EWK_BRINGUP) +IPC_MESSAGE_ROUTED1(EwkViewMsg_SelectionTextStyleState, + SelectionStylePrams /* params */) +#endif + +IPC_MESSAGE_ROUTED2(EwkHostMsg_DidChangeMaxScrollOffset, + int, /*max scrollX*/ + int /*max scrollY*/) + +IPC_MESSAGE_ROUTED2(EwkHostMsg_DidChangeScrollOffset, + int, /*scrollX*/ + int /*scrollY*/) + +#if !defined(EWK_BRINGUP) +IPC_MESSAGE_CONTROL3(EwkViewHostMsg_HitTestReply, + int, /* render_view_id */ + _Ewk_Hit_Test, /* Ewk Hit test data without node map */ + NodeAttributesMap /* node attributes */) + +IPC_MESSAGE_CONTROL4(EwkViewHostMsg_HitTestAsyncReply, + int, /* render_view_id */ + _Ewk_Hit_Test, /* Ewk Hit test data without node map */ + NodeAttributesMap, /* node attributes */ + int64_t /* request id */) +#endif + +IPC_MESSAGE_ROUTED1(EwkViewMsg_GetMHTMLData, + int /* callback id */) + +IPC_MESSAGE_ROUTED2(EwkHostMsg_ReadMHTMLData, + std::string, /* Mhtml text */ + int /* callback id */) + +IPC_MESSAGE_ROUTED1(EwkHostMsg_DidChangePageScaleFactor, + double /* page scale factor */) + +IPC_MESSAGE_ROUTED2(EwkHostMsg_DidChangePageScaleRange, + double, /* minimum page scale factor */ + double /* maximum page scale factor */) + +IPC_MESSAGE_ROUTED1(EwkViewMsg_SetDrawsTransparentBackground, + bool /* enabled */) + +// Notifies the browser to form submit +IPC_MESSAGE_ROUTED1(EwkHostMsg_FormSubmit, GURL) + +IPC_MESSAGE_ROUTED1(EwkViewMsg_WebAppIconUrlGet, + int /* callback id */) + +IPC_MESSAGE_ROUTED2(EwkHostMsg_WebAppIconUrlGet, + std::string, /* icon url */ + int /* callback id */) + +IPC_MESSAGE_ROUTED1(EwkViewMsg_WebAppIconUrlsGet, + int /* callback id */) + +IPC_MESSAGE_ROUTED2(EwkHostMsg_WebAppIconUrlsGet, + StringMap, /* icon urls */ + int /* callback id */) + +IPC_MESSAGE_ROUTED1(EwkViewMsg_WebAppCapableGet, + int /* calback id */) + +IPC_MESSAGE_ROUTED2(EwkHostMsg_WebAppCapableGet, + bool, /* capable */ + int /* calback id */) + +// Used to set view mode. +IPC_MESSAGE_ROUTED1(ViewMsg_SetViewMode, + blink::WebViewMode /* view_mode */) + +#if defined(TIZEN_MULTIMEDIA_SUPPORT) +// This message runs the GStreamer for decoding audio for webaudio. +IPC_MESSAGE_CONTROL3(EflViewHostMsg_GstWebAudioDecode, + base::SharedMemoryHandle /* encoded_data_handle */, + base::FileDescriptor /* pcm_output */, + uint32_t /* data_size*/) +#endif diff --git a/tizen_src/chromium_impl/content/common/wrt/wrt_url_parse.h b/tizen_src/chromium_impl/content/common/wrt/wrt_url_parse.h new file mode 100644 index 000000000000..a695ea9c7151 --- /dev/null +++ b/tizen_src/chromium_impl/content/common/wrt/wrt_url_parse.h @@ -0,0 +1,19 @@ +// Copyright (c) 2014 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WRT_URL_PARSE_H +#define WRT_URL_PARSE_H + +#include "url/gurl.h" + +namespace content { + +class WrtUrlParseBase { + public: + virtual GURL parseUrl(const GURL& url) const = 0; +}; + +} // namespace content + +#endif // WRT_URL_PARSE_H \ No newline at end of file diff --git a/tizen_src/chromium_impl/content/content_efl.gypi b/tizen_src/chromium_impl/content/content_efl.gypi index d91530e1e46a..63dee1733be3 100644 --- a/tizen_src/chromium_impl/content/content_efl.gypi +++ b/tizen_src/chromium_impl/content/content_efl.gypi @@ -7,6 +7,7 @@ 'external_content_common_deps': [ '<(DEPTH)/tizen_src/build/system.gyp:ecore-x', '<(DEPTH)/tizen_src/build/system.gyp:capi-appfw-application', + '<(DEPTH)/tizen_src/build/system.gyp:gstreamer', ], 'external_content_browser_deps': [ '<(DEPTH)/tizen_src/build/system.gyp:ecore', @@ -15,6 +16,7 @@ '<(DEPTH)/tizen_src/build/system.gyp:elementary', '<(DEPTH)/tizen_src/build/system.gyp:efl-assist', '<(DEPTH)/tizen_src/chromium_impl/efl/efl.gyp:window-factory', + '<(DEPTH)/tizen_src/build/system.gyp:gstreamer', ], 'external_content_gpu_deps': [ '<(DEPTH)/tizen_src/build/system.gyp:evas', @@ -31,6 +33,7 @@ '<(DEPTH)/tizen_src/chromium_impl/ui/ui_targets_efl.gyp:ui_native_theme_inject', ], }, + 'target_defaults': { 'target_conditions': [ @@ -42,10 +45,17 @@ 'LOCALE_DIR="<(locale_dir)"', ], 'sources': [ + 'common/cache_params_efl.h', + 'common/navigation_policy_params.cc', + 'common/navigation_policy_params.h', + 'common/message_generator_efl.cc', + 'common/message_generator_efl.h', 'common/paths_efl.h', 'common/paths_efl.cc', + 'common/render_messages_efl.h', 'common/cursors/webcursor_efl.cc', 'common/cursors/webcursor_efl.h', + 'common/wrt/wrt_url_parse.h', ], 'conditions': [ ['building_for_tizen==1', { @@ -62,6 +72,16 @@ [ 'exclude', 'common/gpu/gpu_memory_buffer_factory_linux.cc' ], ] }], + ['tizen_multimedia_support==1', { + 'sources': [ + 'common/media/efl/media_player_messages_enums_efl.h', + 'common/media/efl/media_player_messages_efl.h', + 'common/gpu/media/efl/tizen_video_decode_accelerator.h', + 'common/gpu/media/efl/tizen_video_decode_accelerator.cc', + 'common/gpu/media/efl/tizen_video_encode_accelerator.h', + 'common/gpu/media/efl/tizen_video_encode_accelerator.cc', + ], + }], ], }], @@ -81,13 +101,46 @@ 'browser/renderer_host/web_event_factory_efl.h', 'browser/renderer_host/web_event_factory_efl.cc', ], + 'conditions': [ + ['tizen_multimedia_support==1', { + 'sources': [ + 'browser/media/media_web_contents_observer_efl.cc', + 'browser/media/media_web_contents_observer_efl.h', + 'browser/media/efl/webaudio_decoder_browser_gstreamer.cc', + 'browser/media/efl/webaudio_decoder_browser_gstreamer.h', + 'browser/media/efl/browser_demuxer_efl.cc', + 'browser/media/efl/browser_demuxer_efl.h', + 'browser/media/efl/browser_media_player_manager_efl.cc', + 'browser/media/efl/browser_media_player_manager_efl.h', + ], + }], + ], }], ['_target_name=="content_renderer"', { 'sources': [ + 'renderer/print_pages_params.h', + 'renderer/print_pages_params.cc', '<(DEPTH)/content/renderer/external_popup_menu.cc', '<(DEPTH)/content/renderer/external_popup_menu.h', ], + 'conditions': [ + ['tizen_multimedia_support==1', { + 'sources/': [ + [ 'exclude', 'renderer/media/audio_decoder\\.(cc|h)$' ], + ], + 'sources': [ + 'renderer/media/efl/audio_decoder_gstreamer.cc', + 'renderer/media/efl/audio_decoder_gstreamer.h', + 'renderer/media/efl/media_source_delegate_efl.cc', + 'renderer/media/efl/media_source_delegate_efl.h', + 'renderer/media/efl/renderer_demuxer_efl.cc', + 'renderer/media/efl/renderer_demuxer_efl.h', + 'renderer/media/efl/renderer_media_player_manager_efl.cc', + 'renderer/media/efl/renderer_media_player_manager_efl.h', + ], + }], + ], }], ['_target_name=="content_gpu"', { @@ -115,6 +168,7 @@ [ 'exclude', 'shell/app/shell_main.cc$' ], ], }], - ], - } + + ], # target_conditions + } # target_defaults } diff --git a/tizen_src/chromium_impl/content/renderer/media/efl/audio_decoder_gstreamer.cc b/tizen_src/chromium_impl/content/renderer/media/efl/audio_decoder_gstreamer.cc new file mode 100644 index 000000000000..9163fc48d2a5 --- /dev/null +++ b/tizen_src/chromium_impl/content/renderer/media/efl/audio_decoder_gstreamer.cc @@ -0,0 +1,251 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/renderer/media/efl/audio_decoder_gstreamer.h" + +#include "base/basictypes.h" +#include "base/memory/shared_memory.h" +#include "base/posix/eintr_wrapper.h" +#include "base/process/process.h" +#include "base/strings/string_util.h" +#include "base/time/time.h" +#include "content/common/render_messages_efl.h" +#include "media/base/audio_bus.h" +#include "media/base/limits.h" +#include "public/platform/Platform.h" +#include "third_party/WebKit/public/platform/WebAudioBus.h" +#include "media/base/efl/webaudio_media_codec_info_efl.h" + +namespace content { +//This class is similar as AudioDecoderIO class of Android defined +//in src/content/renderer/media/android/audio_decoder_android.cc +class AudioDecoderIO { + public: + AudioDecoderIO(const char* data, size_t data_size); + ~AudioDecoderIO(); + bool ShareEncodedToProcess(base::SharedMemoryHandle* handle); + + // Returns true if AudioDecoderIO was successfully created. + bool IsValid() const; + + int read_fd() const { return read_fd_; } + int write_fd() const { return write_fd_; } + + private: + // Shared memory that will hold the encoded audio data. This is + // used by MediaCodec for decoding. + base::SharedMemory encoded_shared_memory_; + + // A pipe used to communicate with MediaCodec. MediaCodec owns + // write_fd_ and writes to it. + int read_fd_; + int write_fd_; + + DISALLOW_COPY_AND_ASSIGN(AudioDecoderIO); +}; + +AudioDecoderIO::AudioDecoderIO(const char* data, size_t data_size) + : read_fd_(-1), + write_fd_(-1) { + + if (!data || !data_size || data_size > 0x80000000) + return; + + // Create the shared memory and copy our data to it so that + // MediaCodec can access it. + if(!encoded_shared_memory_.CreateAndMapAnonymous(data_size)) { + LOG(ERROR) << __FUNCTION__ << " Creation of shared memory failed"; + return; + } + + if (!encoded_shared_memory_.memory()) + return; + + memcpy(encoded_shared_memory_.memory(), data, data_size); + + // Create a pipe for reading/writing the decoded PCM data + int pipefd[2]; + + if (pipe(pipefd)) { + LOG(INFO) <<" Pipe is already created"; + return; + } + + read_fd_ = pipefd[0]; + write_fd_ = pipefd[1]; +} + +AudioDecoderIO::~AudioDecoderIO() { + // Close the read end of the pipe. The write end should have been + // closed by MediaCodec. + if (read_fd_ >= 0 && close(read_fd_)) { + LOG(WARNING) << "Cannot close read fd " << read_fd_ + << ": " << strerror(errno); + } +} + +bool AudioDecoderIO::IsValid() const { + return read_fd_ >= 0 && write_fd_ >= 0 && + encoded_shared_memory_.memory(); +} + +bool AudioDecoderIO::ShareEncodedToProcess(base::SharedMemoryHandle* handle) { + return encoded_shared_memory_.ShareToProcess(base::GetCurrentProcessHandle(), + handle); +} + +static float ConvertSampleToFloat(int16_t sample) { + const float kMaxScale = 1.0f / std::numeric_limits::max(); + const float kMinScale = -1.0f / std::numeric_limits::min(); + + return sample * (sample < 0 ? kMinScale : kMaxScale); +} + +static void CopyPcmDataToBus(int input_fd, + blink::WebAudioBus* destination_bus, + size_t num_of_frames, + unsigned number_of_channels, + double file_sample_rate) { + + int16_t pipe_data[PIPE_BUF / sizeof(int16_t)]; + ssize_t nread; + std::vector decoded_samples; + + while ((nread = HANDLE_EINTR(read(input_fd, pipe_data, sizeof(pipe_data)))) > 0) { + size_t samples_in_pipe = nread / sizeof(int16_t); + + if (decoded_samples.size() + samples_in_pipe > decoded_samples.capacity()) { + decoded_samples.reserve(std::max(samples_in_pipe, + 2 * decoded_samples.capacity())); + } + std::copy(pipe_data, + pipe_data + samples_in_pipe, + back_inserter(decoded_samples)); + } + + size_t number_of_samples = decoded_samples.size(); + size_t number_of_frames = decoded_samples.size() / number_of_channels; + size_t decoded_frames = 0; + + destination_bus->initialize(number_of_channels, + number_of_frames, + file_sample_rate); + + for (size_t m = 0; m < number_of_samples; m += number_of_channels) { + for (size_t k = 0; k < number_of_channels; ++k) { + int16_t sample = decoded_samples[m + k]; + destination_bus->channelData(k)[decoded_frames] = + ConvertSampleToFloat(sample); + } + ++decoded_frames; + } + + if (decoded_frames < number_of_frames) + destination_bus->resizeSmaller(decoded_frames); +} + +static void BufferAndCopyPcmDataToBus(int input_fd, + blink::WebAudioBus* destination_bus, + unsigned number_of_channels, + double file_sample_rate) { + int16_t pipe_data[PIPE_BUF / sizeof(int16_t)]; + std::vector decoded_samples; + ssize_t nread; + + while ((nread = HANDLE_EINTR(read(input_fd, pipe_data, sizeof(pipe_data)))) > 0) { + size_t samples_in_pipe = nread / sizeof(int16_t); + if (decoded_samples.size() + samples_in_pipe > decoded_samples.capacity()) { + decoded_samples.reserve(std::max(samples_in_pipe, + 2 * decoded_samples.capacity())); + } + std::copy(pipe_data, + pipe_data + samples_in_pipe, + back_inserter(decoded_samples)); + } + + // Convert the samples and save them in the audio bus. + size_t number_of_samples = decoded_samples.size(); + size_t number_of_frames = decoded_samples.size() / number_of_channels; + size_t decoded_frames = 0; + + destination_bus->initialize(number_of_channels, + number_of_frames, + file_sample_rate); + + for (size_t m = 0; m < number_of_samples; m += number_of_channels) { + for (size_t k = 0; k < number_of_channels; ++k) { + int16_t sample = decoded_samples[m + k]; + destination_bus->channelData(k)[decoded_frames] = + ConvertSampleToFloat(sample); + } + ++decoded_frames; + } + + // number_of_frames is only an estimate. Resize the buffer with the + // actual number of received frames. + if (decoded_frames < number_of_frames) + destination_bus->resizeSmaller(decoded_frames); +} + +// Decode in-memory audio file data. +bool DecodeAudioFileData(blink::WebAudioBus* destination_bus, + const char* data, + size_t data_size, + scoped_refptr sender) { + AudioDecoderIO audio_decoder(data, data_size); + + if (!audio_decoder.IsValid()) { + LOG(ERROR) << "Invalid audio_decoder"; + return false; + } + + base::SharedMemoryHandle encoded_data_handle; + audio_decoder.ShareEncodedToProcess(&encoded_data_handle); + base::FileDescriptor fd(audio_decoder.write_fd(), true); + + // Start Decoding in the browser which will read from + // encoded_data_handle for our shared memory and write the decoded + // PCM samples (16-bit integer) to our pipe. + + sender->Send(new EflViewHostMsg_GstWebAudioDecode(encoded_data_handle, fd, data_size)); + + int input_fd = audio_decoder.read_fd(); + struct media::WebAudioMediaCodecInfoEfl info; + + ssize_t nread = HANDLE_EINTR(read(input_fd, &info, sizeof(info))); + + if (nread != sizeof(info)) { + LOG(ERROR) << "Read Failed"; + return false; + } + + unsigned number_of_channels = info.channel_count; + double file_sample_rate = static_cast(info.sample_rate); + size_t number_of_frames = info.number_of_frames; + + // Sanity checks + if (!number_of_channels || + number_of_channels > media::limits::kMaxChannels || + file_sample_rate < media::limits::kMinSampleRate || + file_sample_rate > media::limits::kMaxSampleRate) { + return false; + } + + if (number_of_frames > 0) { + CopyPcmDataToBus(input_fd, + destination_bus, + number_of_frames, + number_of_channels, + file_sample_rate); + } else { + BufferAndCopyPcmDataToBus(input_fd, + destination_bus, + number_of_channels, + file_sample_rate); + } + + return true; +} + +} // namespace content diff --git a/tizen_src/chromium_impl/content/renderer/media/efl/audio_decoder_gstreamer.h b/tizen_src/chromium_impl/content/renderer/media/efl/audio_decoder_gstreamer.h new file mode 100644 index 000000000000..c937ee7b18ee --- /dev/null +++ b/tizen_src/chromium_impl/content/renderer/media/efl/audio_decoder_gstreamer.h @@ -0,0 +1,10 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_RENDERER_MEDIA_TIZEN_AUDIO_DECODER_GSTREAMER_H_ +#define CONTENT_RENDERER_MEDIA_TIZEN_AUDIO_DECODER_GSTREAMER_H_ + +#include "content/renderer/media/android/audio_decoder_android.h" + +#endif // CONTENT_RENDERER_MEDIA_TIZEN_AUDIO_DECODER_GSTREAMER_H_ \ No newline at end of file diff --git a/tizen_src/chromium_impl/content/renderer/media/efl/media_source_delegate_efl.cc b/tizen_src/chromium_impl/content/renderer/media/efl/media_source_delegate_efl.cc new file mode 100644 index 000000000000..aa251f1ba3f3 --- /dev/null +++ b/tizen_src/chromium_impl/content/renderer/media/efl/media_source_delegate_efl.cc @@ -0,0 +1,514 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/renderer/media/efl/media_source_delegate_efl.h" + +#include "base/process/process.h" +#include "media/base/bind_to_current_loop.h" +#include "media/base/media_log.h" +#include "media/base/efl/demuxer_stream_player_params_efl.h" +#include "media/blink/webmediaplayer_util.h" +#include "media/blink/webmediasource_impl.h" +#include "media/filters/chunk_demuxer.h" +#include "media/filters/decrypting_demuxer_stream.h" +#include "third_party/WebKit/public/web/WebRuntimeFeatures.h" + +namespace content { + +static void LogMediaSourceError( + const scoped_refptr& media_log, + const std::string& error) { + media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error)); +} + +MediaSourceDelegateEfl::MediaSourceDelegateEfl( + RendererDemuxerEfl* demuxer_client, + int demuxer_client_id, + const scoped_refptr& media_task_runner, + media::MediaLog* media_log) + : main_loop_(base::MessageLoopProxy::current()), + main_weak_factory_(this), + main_weak_this_(main_weak_factory_.GetWeakPtr()), + media_task_runner_(media_task_runner), + media_weak_factory_(this), + demuxer_client_(demuxer_client), + demuxer_client_id_(demuxer_client_id), + media_log_(media_log), + audio_stream_(NULL), + video_stream_(NULL), + seek_time_(media::kNoTimestamp()), + pending_seek_(false), + is_seeking_(false), + seeking_pending_seek_(false), + is_demuxer_seek_done_(false), + pending_seek_time_(media::kNoTimestamp()), + is_audio_read_fired_(false), + is_video_read_fired_(false), + is_demuxer_ready_(false), + shared_memory_size_(0) { + VLOG(1) << "MediaSourceDelegateEfl::" << __FUNCTION__ + << ": Demuxer Client Id = " << demuxer_client_id_; + DCHECK(!chunk_demuxer_); +} + +MediaSourceDelegateEfl::~MediaSourceDelegateEfl() { + DCHECK(main_loop_->BelongsToCurrentThread()); + DCHECK(!chunk_demuxer_); + DCHECK(!audio_stream_); + DCHECK(!video_stream_); + DCHECK(!audio_decrypting_demuxer_stream_); + DCHECK(!video_decrypting_demuxer_stream_); +} + +void MediaSourceDelegateEfl::InitializeMediaSource( + const MediaSourceOpenedCB& media_source_opened_cb, + const media::Demuxer::NeedKeyCB& need_key_cb, + const media::SetDecryptorReadyCB& set_decryptor_ready_cb, + const UpdateNetworkStateCB& update_network_state_cb, + const DurationChangeCB& duration_change_cb) { + DCHECK(main_loop_->BelongsToCurrentThread()); + DCHECK(!media_source_opened_cb.is_null()); + media_source_opened_cb_ = media_source_opened_cb; + need_key_cb_ = need_key_cb; + set_decryptor_ready_cb_ = set_decryptor_ready_cb; + update_network_state_cb_ = media::BindToCurrentLoop(update_network_state_cb); + duration_change_cb_ = duration_change_cb; + + chunk_demuxer_.reset(new media::ChunkDemuxer( + media::BindToCurrentLoop(base::Bind( + &MediaSourceDelegateEfl::OnDemuxerOpened, main_weak_this_)), + media::BindToCurrentLoop(base::Bind( + &MediaSourceDelegateEfl::OnNeedKey, main_weak_this_)), + base::Bind(&LogMediaSourceError, media_log_), + false)); + + media_task_runner_->PostTask(FROM_HERE, + base::Bind(&MediaSourceDelegateEfl::InitializeDemuxer, + base::Unretained(this))); +} + +void MediaSourceDelegateEfl::InitializeDemuxer() { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + demuxer_client_->AddDelegate(demuxer_client_id_, this); + chunk_demuxer_->Initialize( + this, + base::Bind(&MediaSourceDelegateEfl::OnDemuxerInitDone, + media_weak_factory_.GetWeakPtr()), + false); +} + +void MediaSourceDelegateEfl::OnNeedKey( + const std::string& type, + const std::vector& init_data) { + DCHECK(main_loop_->BelongsToCurrentThread()); + if (need_key_cb_.is_null()) { + return; + } + need_key_cb_.Run(type, init_data); +} + +void MediaSourceDelegateEfl::OnDemuxerOpened() { + DCHECK(main_loop_->BelongsToCurrentThread()); + if (media_source_opened_cb_.is_null()) + return; + media_source_opened_cb_.Run(new media::WebMediaSourceImpl( + chunk_demuxer_.get(), base::Bind(&LogMediaSourceError, media_log_))); +} + +void MediaSourceDelegateEfl::OnDemuxerError( + media::PipelineStatus status) { + if (status != media::PIPELINE_OK && !update_network_state_cb_.is_null()) + update_network_state_cb_.Run(PipelineErrorToNetworkState(status)); +} + +void MediaSourceDelegateEfl::OnDemuxerInitDone( + media::PipelineStatus status) { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + DCHECK(chunk_demuxer_); + if (status != media::PIPELINE_OK) { + OnDemuxerError(status); + return; + } + audio_stream_ = chunk_demuxer_->GetStream(media::DemuxerStream::AUDIO); + video_stream_ = chunk_demuxer_->GetStream(media::DemuxerStream::VIDEO); + if (audio_stream_ && audio_stream_->audio_decoder_config().is_encrypted() && + !set_decryptor_ready_cb_.is_null()) { + InitAudioDecryptingDemuxerStream(); + return; + } + if (video_stream_ && video_stream_->video_decoder_config().is_encrypted() && + !set_decryptor_ready_cb_.is_null()) { + InitVideoDecryptingDemuxerStream(); + return; + } + // Notify demuxer ready when both streams are not encrypted. + is_demuxer_ready_ = true; + NotifyDemuxerReady(); +} + +void MediaSourceDelegateEfl::InitAudioDecryptingDemuxerStream() { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + audio_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream( + media_task_runner_, set_decryptor_ready_cb_)); + + audio_decrypting_demuxer_stream_->Initialize( + audio_stream_, + base::Bind(&MediaSourceDelegateEfl::OnAudioDecryptingDemuxerStreamInitDone, + media_weak_factory_.GetWeakPtr())); +} + +void MediaSourceDelegateEfl::InitVideoDecryptingDemuxerStream() { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + + video_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream( + media_task_runner_, set_decryptor_ready_cb_)); + + video_decrypting_demuxer_stream_->Initialize( + video_stream_, + base::Bind(&MediaSourceDelegateEfl::OnVideoDecryptingDemuxerStreamInitDone, + media_weak_factory_.GetWeakPtr())); +} + + +void MediaSourceDelegateEfl::OnAudioDecryptingDemuxerStreamInitDone( + media::PipelineStatus status) { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + DCHECK(chunk_demuxer_); + + if (status != media::PIPELINE_OK) + audio_decrypting_demuxer_stream_.reset(); + else + audio_stream_ = audio_decrypting_demuxer_stream_.get(); + + if (video_stream_ && video_stream_->video_decoder_config().is_encrypted()) { + InitVideoDecryptingDemuxerStream(); + return; + } + + // Try to notify demuxer ready when audio DDS initialization finished and + // video is not encrypted. + is_demuxer_ready_ = true; + NotifyDemuxerReady(); +} + +void MediaSourceDelegateEfl::OnVideoDecryptingDemuxerStreamInitDone( + media::PipelineStatus status) { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + DCHECK(chunk_demuxer_); + + if (status != media::PIPELINE_OK) + video_decrypting_demuxer_stream_.reset(); + else + video_stream_ = video_decrypting_demuxer_stream_.get(); + + // Try to notify demuxer ready when video DDS initialization finished. + is_demuxer_ready_ = true; + NotifyDemuxerReady(); +} + +void MediaSourceDelegateEfl::NotifyDemuxerReady() { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + DCHECK(is_demuxer_ready_); + + scoped_ptr configs(new media::DemuxerConfigs()); + if (audio_stream_) { + media::AudioDecoderConfig audio_config = + audio_stream_->audio_decoder_config(); + configs->audio_codec = audio_config.codec(); + configs->audio_channels = + media::ChannelLayoutToChannelCount(audio_config.channel_layout()); + configs->audio_sampling_rate = audio_config.samples_per_second(); + configs->is_audio_encrypted = audio_config.is_encrypted(); + configs->audio_extra_data = std::vector(audio_config.extra_data(), + audio_config.extra_data() + audio_config.extra_data_size()); + } + if (video_stream_) { + media::VideoDecoderConfig video_config = + video_stream_->video_decoder_config(); + configs->video_codec = video_config.codec(); + configs->video_size = video_config.natural_size(); + configs->is_video_encrypted = video_config.is_encrypted(); + configs->video_extra_data = std::vector(video_config.extra_data(), + video_config.extra_data() + video_config.extra_data_size()); + } + if (demuxer_client_) { + demuxer_client_->DemuxerReady(demuxer_client_id_, *configs); + } +} + +void MediaSourceDelegateEfl::OnReadFromDemuxer( + media::DemuxerStream::Type type) { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + + if (is_seeking_) + return; + + if ((type == media::DemuxerStream::AUDIO) && audio_stream_ + && !is_audio_read_fired_) { + is_audio_read_fired_ = true; + audio_stream_->Read(base::Bind( + &MediaSourceDelegateEfl::OnBufferReady, + media_weak_factory_.GetWeakPtr() , type)); + } + + if ((type == media::DemuxerStream::VIDEO) && video_stream_ + && !is_video_read_fired_) { + is_video_read_fired_ = true; + video_stream_->Read(base::Bind( + &MediaSourceDelegateEfl::OnBufferReady, + media_weak_factory_.GetWeakPtr() , type)); + } +} + +void MediaSourceDelegateEfl::Stop(const base::Closure& stop_cb) { + DCHECK(main_loop_->BelongsToCurrentThread()); + VLOG(1) << "MediaSourceDelegateEfl::" << __FUNCTION__ + << ": Demuxer Client Id = " << demuxer_client_id_; + + if (!chunk_demuxer_) { + DCHECK(!demuxer_client_); + return; + } + + duration_change_cb_.Reset(); + update_network_state_cb_.Reset(); + media_source_opened_cb_.Reset(); + + main_weak_factory_.InvalidateWeakPtrs(); + DCHECK(!main_weak_factory_.HasWeakPtrs()); + + // 1. shutdown demuxer. + // 2. On media thread, call stop demuxer. + // 3. On callback, post message and self destory. + chunk_demuxer_->Shutdown(); + media_task_runner_->PostTask( + FROM_HERE, + base::Bind(&MediaSourceDelegateEfl::StopDemuxer, + base::Unretained(this), + stop_cb)); +} + +void MediaSourceDelegateEfl::StopDemuxer(const base::Closure& stop_cb) { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + DCHECK(chunk_demuxer_); + + demuxer_client_->RemoveDelegate(demuxer_client_id_); + demuxer_client_ = NULL; + audio_stream_ = NULL; + video_stream_ = NULL; + audio_decrypting_demuxer_stream_.reset(); + video_decrypting_demuxer_stream_.reset(); + + media_weak_factory_.InvalidateWeakPtrs(); + DCHECK(!media_weak_factory_.HasWeakPtrs()); + + chunk_demuxer_->Stop(); + chunk_demuxer_.reset(); + + stop_cb.Run(); +} + +void MediaSourceDelegateEfl::OnMediaConfigRequest() { + NotifyDemuxerReady(); +} + +void MediaSourceDelegateEfl::SeekInternal( + const base::TimeDelta& seek_time) { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + chunk_demuxer_->Seek(seek_time, base::Bind( + &MediaSourceDelegateEfl::OnDemuxerSeekDone, + media_weak_factory_.GetWeakPtr())); +} + +void MediaSourceDelegateEfl::OnBufferReady( + media::DemuxerStream::Type type, + media::DemuxerStream::Status status, + const scoped_refptr& buffer) { + + scoped_ptr meta_data( + new media::DemuxedBufferMetaData()); + meta_data->status = status; + meta_data->type = type; + + if (type == media::DemuxerStream::AUDIO) + is_audio_read_fired_ = false; + if (type == media::DemuxerStream::VIDEO) + is_video_read_fired_ = false; + + switch (status) { + case media::DemuxerStream::kAborted: + LOG (ERROR) << "[RENDER] : DemuxerStream::kAborted"; + break; + + case media::DemuxerStream::kConfigChanged: + VLOG(1) << "[RENDER] : DemuxerStream::kConfigChanged"; + NotifyDemuxerReady(); + break; + + case media::DemuxerStream::kOk: + if (buffer.get()->end_of_stream()) { + VLOG(1) << "[RENDER] : DemuxerStream::kOk but |end_of_stream|"; + meta_data->end_of_stream = true; + break; + } + shared_memory_size_ = buffer.get()->data_size(); + if (!shared_memory_.CreateAndMapAnonymous(shared_memory_size_)) { + LOG (ERROR) << "Shared Memory creation failed."; + return; + } + if (!shared_memory_.ShareToProcess(base::Process::Current().Handle(), + &foreign_memory_handle_)) { + LOG (ERROR) << "Shared Memory handle could not be obtained"; + shared_memory_.Close(); + return; + } + memcpy(shared_memory_.memory(), (void*)buffer.get()->writable_data(), + shared_memory_size_); + meta_data->timestamp = buffer.get()->timestamp(); + meta_data->time_duration = buffer.get()->duration(); + if (demuxer_client_) { + meta_data->size = shared_memory_size_; + demuxer_client_->ReadFromDemuxerAck( + demuxer_client_id_, foreign_memory_handle_, *meta_data); + } + shared_memory_.Close(); + return; + break; + default: + NOTREACHED(); + } + + if (demuxer_client_) + demuxer_client_->BufferMetaDataAck(demuxer_client_id_, *meta_data); +} + +void MediaSourceDelegateEfl::StartWaitingForSeek( + const base::TimeDelta& seek_time) { + DCHECK(main_loop_->BelongsToCurrentThread()); + + if (!chunk_demuxer_) + return; + // Called from |webmediaplayertizen| only. + is_demuxer_seek_done_ = false; + seeking_pending_seek_ = false; + is_seeking_ = true; + chunk_demuxer_->StartWaitingForSeek(seek_time); +} + +void MediaSourceDelegateEfl::CancelPendingSeek( + const base::TimeDelta& seek_time) { + DCHECK(main_loop_->BelongsToCurrentThread()); + if (!chunk_demuxer_) + return; + is_seeking_ = true; + pending_seek_ = true; + pending_seek_time_ = seek_time; + + if (is_demuxer_seek_done_) { + // Since we already requested gstreamer to seek. And there are no pending + // seeks in |chunk_demuxer|. Cancelling pending seek makes no sense. + // + // This block will handle when |gstreamer| is seeking and new seek came in + // between. + VLOG(1) << "No need to CancelPendingSeek"; + is_demuxer_seek_done_ = false; + pending_seek_ = false; + chunk_demuxer_->StartWaitingForSeek(seek_time); + StartSeek(seek_time, true); + return; + } + + chunk_demuxer_->CancelPendingSeek(seek_time); +} + +void MediaSourceDelegateEfl::StartSeek( + const base::TimeDelta& seek_time, + bool is_seeking_pending_seek) { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + + VLOG(1)<< "MediaSourceDelegateEfl::" << __FUNCTION__ + << " : " << seek_time.InSecondsF(); + if (!chunk_demuxer_) + return; + is_seeking_ = true; + is_demuxer_seek_done_ = false; + if (is_seeking_pending_seek) + seeking_pending_seek_ = is_seeking_pending_seek; + else if (seeking_pending_seek_) { + VLOG(1)<< "Ignoring seek request from Efl"; + return; + } + seek_time_ = seek_time; + SeekInternal(seek_time); +} + +void MediaSourceDelegateEfl::OnDemuxerSeekDone( + media::PipelineStatus status) { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + if (status != media::PIPELINE_OK) { + OnDemuxerError(status); + return; + } + if (pending_seek_) { + pending_seek_ = false; + StartSeek(pending_seek_time_, true); + seek_time_ = pending_seek_time_; + } else { + VLOG(1) << "Actual time that Gstreamer seeks : " + << seek_time_.InMilliseconds(); + seeking_pending_seek_ = false; + is_seeking_ = false; + is_demuxer_seek_done_ = true; + demuxer_client_->DemuxerSeekDone(demuxer_client_id_, seek_time_); + } + ResetAudioDecryptingDemuxerStream(); +} + +void MediaSourceDelegateEfl::ResetAudioDecryptingDemuxerStream() { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + if (audio_decrypting_demuxer_stream_) { + audio_decrypting_demuxer_stream_->Reset( + base::Bind(&MediaSourceDelegateEfl::ResetVideoDecryptingDemuxerStream, + media_weak_factory_.GetWeakPtr())); + return; + } + ResetVideoDecryptingDemuxerStream(); +} + +void MediaSourceDelegateEfl::ResetVideoDecryptingDemuxerStream() { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + if (video_decrypting_demuxer_stream_) { + video_decrypting_demuxer_stream_->Reset(base::Bind( + &MediaSourceDelegateEfl::FinishResettingDecryptingDemuxerStreams, + media_weak_factory_.GetWeakPtr())); + return; + } + FinishResettingDecryptingDemuxerStreams(); +} + +void MediaSourceDelegateEfl::FinishResettingDecryptingDemuxerStreams() { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + DCHECK(is_seeking_); + is_seeking_ = false; + demuxer_client_->DemuxerSeekDone(demuxer_client_id_, seek_time_); +} + +void MediaSourceDelegateEfl::SetDuration(base::TimeDelta duration) { + DCHECK(main_loop_->BelongsToCurrentThread()); + main_loop_->PostTask(FROM_HERE, base::Bind( + &MediaSourceDelegateEfl::OnDurationChanged, + main_weak_this_, duration)); +} + +void MediaSourceDelegateEfl::OnDurationChanged( + const base::TimeDelta& duration) { + DCHECK(main_loop_->BelongsToCurrentThread()); + if (demuxer_client_) + demuxer_client_->DurationChanged(demuxer_client_id_, duration); + + if (!duration_change_cb_.is_null()) + duration_change_cb_.Run(duration.InSecondsF()); +} + +} // namespace content diff --git a/tizen_src/chromium_impl/content/renderer/media/efl/media_source_delegate_efl.h b/tizen_src/chromium_impl/content/renderer/media/efl/media_source_delegate_efl.h new file mode 100644 index 000000000000..a388c6b605d1 --- /dev/null +++ b/tizen_src/chromium_impl/content/renderer/media/efl/media_source_delegate_efl.h @@ -0,0 +1,171 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_RENDERER_MEDIA_TIZEN_MEDIA_SOURCE_DELEGATE_EFL_H_ +#define CONTENT_RENDERER_MEDIA_TIZEN_MEDIA_SOURCE_DELEGATE_EFL_H_ + +#include "content/renderer/media/efl/renderer_demuxer_efl.h" +#include "media/base/decoder_buffer.h" +#include "media/base/demuxer_stream.h" +#include "media/base/media_keys.h" +#include "media/filters/chunk_demuxer.h" +#include "media/filters/decrypting_demuxer_stream.h" +#include "third_party/WebKit/public/platform/WebMediaPlayer.h" + +namespace content { + +class MediaSourceDelegateEfl + : public media::DemuxerHost { +public: + typedef base::Callback + MediaSourceOpenedCB; + typedef base::Callback + UpdateNetworkStateCB; + typedef base::Callback DurationChangeCB; + + MediaSourceDelegateEfl( + RendererDemuxerEfl* demuxer_client, + int demuxer_client_id, + const scoped_refptr& media_task_runner, + media::MediaLog* media_log); + ~MediaSourceDelegateEfl(); + + //DemuxerHost implementation. + virtual void AddBufferedTimeRange( + base::TimeDelta start, + base::TimeDelta end) override {}; + + // Sets the duration of the media in microseconds. + // Duration may be kInfiniteDuration() if the duration is not known. + virtual void SetDuration(base::TimeDelta duration) override; + + // Stops execution of the pipeline due to a fatal error. Do not call this + // method with PIPELINE_OK. + virtual void OnDemuxerError(media::PipelineStatus error) override; + + // Add |text_stream| to the collection managed by the text renderer. + virtual void AddTextStream( + media::DemuxerStream* text_stream, + const media::TextTrackConfig& config) override {}; + + // Remove |text_stream| from the presentation. + virtual void RemoveTextStream(media::DemuxerStream* text_stream) override {}; + + void InitializeMediaSource( + const MediaSourceOpenedCB& media_source_opened_cb, + const media::Demuxer::NeedKeyCB& need_key_cb, + const media::SetDecryptorReadyCB& set_decryptor_ready_cb, + const UpdateNetworkStateCB& update_network_state_cb, + const DurationChangeCB& duration_change_cb); + + // Called when DemuxerStreamPlayer needs to read data from ChunkDemuxer. + void OnReadFromDemuxer(media::DemuxerStream::Type type); + + // Must be called explicitly before |this| can be destroyed. + void Stop(const base::Closure& stop_cb); + + // In MSE case, calls ChunkDemuxer::StartWaitingForSeek(), sets the + // expectation that a regular seek will be arriving. + void StartWaitingForSeek(const base::TimeDelta& seek_time); + + // Calls ChunkDemuxer::CancelPendingSeek(). Also sets the + // expectation that a regular seek will be arriving. + void CancelPendingSeek(const base::TimeDelta& seek_time); + + // Sets the expectation that a regular seek will be arriving. + void StartSeek( + const base::TimeDelta& seek_time, + bool is_seeking_pending_seek); + + // Callback for ChunkDemuxer::Seek() and callback chain for resetting + // decrypted audio/video streams if present. + // + // Runs on the media thread. + void OnDemuxerSeekDone(media::PipelineStatus status); + + // Called when the player needs the new config data from ChunkDemuxer. + void OnMediaConfigRequest(); + + private: + void OnNeedKey(const std::string& type, const std::vector& init_data); + void OnDemuxerOpened(); + void InitializeDemuxer(); + void OnDemuxerInitDone(media::PipelineStatus status); + + // Stops and clears objects on the media thread. + void StopDemuxer(const base::Closure& stop_cb); + + void NotifyDemuxerReady(); + void OnDurationChanged(const base::TimeDelta& duration); + void OnBufferReady( + media::DemuxerStream::Type type, + media::DemuxerStream::Status status, + const scoped_refptr& buffer); + void SeekInternal(const base::TimeDelta& seek_time); + + // Initializes DecryptingDemuxerStreams if audio/video stream is encrypted. + void InitAudioDecryptingDemuxerStream(); + void InitVideoDecryptingDemuxerStream(); + + // Callbacks for DecryptingDemuxerStream::Initialize(). + void OnAudioDecryptingDemuxerStreamInitDone(media::PipelineStatus status); + void OnVideoDecryptingDemuxerStreamInitDone(media::PipelineStatus status); + + // Runs on the media thread. + void ResetAudioDecryptingDemuxerStream(); + void ResetVideoDecryptingDemuxerStream(); + void FinishResettingDecryptingDemuxerStreams(); + + // Message loop for main renderer thread and corresponding weak pointer. + const scoped_refptr main_loop_; + base::WeakPtrFactory main_weak_factory_; + base::WeakPtr main_weak_this_; + + // Message loop for media thread and corresponding weak pointer. + const scoped_refptr media_task_runner_; + base::WeakPtrFactory media_weak_factory_; + RendererDemuxerEfl* demuxer_client_; + int demuxer_client_id_; + scoped_refptr media_log_; + + MediaSourceOpenedCB media_source_opened_cb_; + UpdateNetworkStateCB update_network_state_cb_; + DurationChangeCB duration_change_cb_; + + scoped_ptr chunk_demuxer_; + media::DemuxerStream* audio_stream_; + media::DemuxerStream* video_stream_; + + media::SetDecryptorReadyCB set_decryptor_ready_cb_; + media::Demuxer::NeedKeyCB need_key_cb_; + scoped_ptr audio_decrypting_demuxer_stream_; + scoped_ptr video_decrypting_demuxer_stream_; + + base::TimeDelta seek_time_; + bool pending_seek_; + bool is_seeking_; + + // Will handle internal seek coming from |MediaSourcePlayerGstreamer| + // if new seek has been fired by |HTMLMediaElement|. + // Always one should seek to latest time and ignore previous seeks. + bool seeking_pending_seek_; + + // Will handle |seek| request coming after |chunk_demuxer| + // has requested |gstreamer| to seek. + bool is_demuxer_seek_done_; + base::TimeDelta pending_seek_time_; + + bool is_audio_read_fired_; + bool is_video_read_fired_; + + bool is_demuxer_ready_; + + uint32 shared_memory_size_; + base::SharedMemory shared_memory_; + base::SharedMemoryHandle foreign_memory_handle_; +}; + +} // namespace content + +#endif // CONTENT_RENDERER_MEDIA_TIZEN_MEDIA_SOURCE_DELEGATE_EFL_H_ diff --git a/tizen_src/chromium_impl/content/renderer/media/efl/renderer_demuxer_efl.cc b/tizen_src/chromium_impl/content/renderer/media/efl/renderer_demuxer_efl.cc new file mode 100644 index 000000000000..1dcc2c67160d --- /dev/null +++ b/tizen_src/chromium_impl/content/renderer/media/efl/renderer_demuxer_efl.cc @@ -0,0 +1,120 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/renderer/media/efl/renderer_demuxer_efl.h" + +#include "base/bind.h" +#include "base/message_loop/message_loop.h" +#include "content/child/thread_safe_sender.h" +#include "content/common/media/efl/media_player_messages_efl.h" +#include "content/renderer/media/efl/media_source_delegate_efl.h" +#include "content/renderer/media/efl/renderer_media_player_manager_efl.h" +#include "content/renderer/render_thread_impl.h" + +namespace content { + +RendererDemuxerEfl::RendererDemuxerEfl() + : thread_safe_sender_(RenderThreadImpl::current()->thread_safe_sender()), + media_task_runner_( + RenderThreadImpl::current()->GetMediaThreadTaskRunner()) {} + +RendererDemuxerEfl::~RendererDemuxerEfl() {} + +int RendererDemuxerEfl::GetNextDemuxerClientID() { + // Don't use zero for IDs since it can be interpreted as having no ID. + return next_demuxer_client_id_.GetNext() + 1; +} + +void RendererDemuxerEfl::AddDelegate( + int demuxer_client_id, + MediaSourceDelegateEfl* delegate) { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + delegates_.AddWithID(delegate, demuxer_client_id); +} + +void RendererDemuxerEfl::RemoveDelegate(int demuxer_client_id) { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + delegates_.Remove(demuxer_client_id); +} + +bool RendererDemuxerEfl::OnMessageReceived(const IPC::Message& message) { + switch (message.type()) { + case MediaPlayerGstMsg_ReadFromDemuxer::ID: + case MediaPlayerGstMsg_MediaConfigRequest::ID: + case MediaPlayerGstMsg_DemuxerSeekRequest::ID: + media_task_runner_->PostTask(FROM_HERE, base::Bind( + &RendererDemuxerEfl::DispatchMessage, this, message)); + return true; + } + return false; +} + +void RendererDemuxerEfl::DemuxerReady( + int demuxer_client_id, + const media::DemuxerConfigs& configs) { + thread_safe_sender_->Send(new MediaPlayerGstHostMsg_DemuxerReady( + demuxer_client_id, configs)); +} + +void RendererDemuxerEfl::ReadFromDemuxerAck( + int demuxer_client_id, + base::SharedMemoryHandle foreign_memory_handle, + const media::DemuxedBufferMetaData& meta_data) { + thread_safe_sender_->Send(new MediaPlayerGstHostMsg_ReadFromDemuxerAck( + demuxer_client_id, foreign_memory_handle, meta_data)); +} + +void RendererDemuxerEfl::BufferMetaDataAck( + int demuxer_client_id, + const media::DemuxedBufferMetaData& meta_data) { + thread_safe_sender_->Send(new MediaPlayerGstHostMsg_BufferMetaDataAck( + demuxer_client_id, meta_data)); +} + +void RendererDemuxerEfl::DemuxerSeekDone( + int demuxer_client_id, + const base::TimeDelta& actual_browser_seek_time) { + thread_safe_sender_->Send(new MediaPlayerGstHostMsg_DemuxerSeekDone( + demuxer_client_id, actual_browser_seek_time)); +} + +void RendererDemuxerEfl::DurationChanged(int demuxer_client_id, + const base::TimeDelta& duration) { + thread_safe_sender_->Send(new MediaPlayerGstHostMsg_DurationChanged( + demuxer_client_id, duration)); +} + +void RendererDemuxerEfl::DispatchMessage(const IPC::Message& message) { + IPC_BEGIN_MESSAGE_MAP(RendererDemuxerEfl, message) + IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_ReadFromDemuxer, OnReadFromDemuxer) + IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_MediaConfigRequest, + OnMediaConfigRequest) + IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_DemuxerSeekRequest, + OnDemuxerSeekRequest) + IPC_END_MESSAGE_MAP() +} + +void RendererDemuxerEfl::OnReadFromDemuxer( + int demuxer_client_id, + media::DemuxerStream::Type type) { + MediaSourceDelegateEfl* delegate = delegates_.Lookup(demuxer_client_id); + if (delegate) + delegate->OnReadFromDemuxer(type); +} + +void RendererDemuxerEfl::OnDemuxerSeekRequest( + int demuxer_client_id, + const base::TimeDelta& time_to_seek) { + MediaSourceDelegateEfl* delegate = delegates_.Lookup(demuxer_client_id); + if (delegate) + delegate->StartSeek(time_to_seek, false); +} + +void RendererDemuxerEfl::OnMediaConfigRequest(int demuxer_client_id) { + MediaSourceDelegateEfl* delegate = delegates_.Lookup(demuxer_client_id); + if (delegate) + delegate->OnMediaConfigRequest(); +} + +} // namespace content diff --git a/tizen_src/chromium_impl/content/renderer/media/efl/renderer_demuxer_efl.h b/tizen_src/chromium_impl/content/renderer/media/efl/renderer_demuxer_efl.h new file mode 100644 index 000000000000..21b0444349ec --- /dev/null +++ b/tizen_src/chromium_impl/content/renderer/media/efl/renderer_demuxer_efl.h @@ -0,0 +1,90 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_RENDERER_MEDIA_TIZEN_RENDERER_DEMUXER_EFL_H_ +#define CONTENT_RENDERER_MEDIA_TIZEN_RENDERER_DEMUXER_EFL_H_ + +#include "base/atomic_sequence_num.h" +#include "base/id_map.h" +#include "ipc/message_filter.h" +#include "media/base/efl/demuxer_stream_player_params_efl.h" + +namespace base { +class SingleThreadTaskRunner; +} + +namespace content { + +class MediaSourceDelegateEfl; +class ThreadSafeSender; + +// Represents the renderer process half of an IPC-based implementation of +// media::DemuxerEfl. +// +// Refer to BrowserDemuxerEfl for the browser process half. +class RendererDemuxerEfl : public IPC::MessageFilter { + public: + RendererDemuxerEfl(); + + // Returns the next available demuxer client ID for use in IPC messages. + // + // Safe to call on any thread. + int GetNextDemuxerClientID(); + + // Associates |delegate| with |demuxer_client_id| for handling incoming IPC + // messages. + // + // Must be called on media thread. + void AddDelegate( + int demuxer_client_id, + MediaSourceDelegateEfl* delegate); + + // Removes the association created by AddDelegate(). + // + // Must be called on media thread. + void RemoveDelegate(int demuxer_client_id); + + // IPC::ChannelProxy::MessageFilter overrides. + virtual bool OnMessageReceived(const IPC::Message& message) override; + + // media::DemuxerEflClient "implementation". + void DemuxerReady( + int demuxer_client_id, + const media::DemuxerConfigs& configs); + void ReadFromDemuxerAck( + int demuxer_client_id, + base::SharedMemoryHandle foreign_memory_handle, + const media::DemuxedBufferMetaData& meta_data); + void BufferMetaDataAck( + int demuxer_client_id, + const media::DemuxedBufferMetaData& meta_data); + void DemuxerSeekDone( + int demuxer_client_id, + const base::TimeDelta& actual_browser_seek_time); + void DurationChanged(int demuxer_client_id, const base::TimeDelta& duration); + + protected: + friend class base::RefCountedThreadSafe; + virtual ~RendererDemuxerEfl(); + + private: + void DispatchMessage(const IPC::Message& message); + void OnReadFromDemuxer(int demuxer_client_id, + media::DemuxerStream::Type type); + void OnDemuxerSeekRequest(int demuxer_client_id, + const base::TimeDelta& time_to_seek); + void OnMediaConfigRequest(int demuxer_client_id); + + base::AtomicSequenceNumber next_demuxer_client_id_; + + IDMap delegates_; + scoped_refptr thread_safe_sender_; + scoped_refptr media_task_runner_; + + DISALLOW_COPY_AND_ASSIGN(RendererDemuxerEfl); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_MEDIA_TIZEN_RENDERER_DEMUXER_EFL_H_ diff --git a/tizen_src/chromium_impl/content/renderer/media/efl/renderer_media_player_manager_efl.cc b/tizen_src/chromium_impl/content/renderer/media/efl/renderer_media_player_manager_efl.cc new file mode 100644 index 000000000000..a56c248dce25 --- /dev/null +++ b/tizen_src/chromium_impl/content/renderer/media/efl/renderer_media_player_manager_efl.cc @@ -0,0 +1,229 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/renderer/media/efl/renderer_media_player_manager_efl.h" + +#include "base/bind.h" +#include "base/message_loop/message_loop.h" +#include "content/common/media/efl/media_player_messages_efl.h" +#include "ui/gfx/rect_f.h" + +namespace content { + +RendererMediaPlayerManagerEfl::RendererMediaPlayerManagerEfl( + RenderFrame* render_frame) + : RenderFrameObserver(render_frame), + next_media_player_id_(0) { +} + +RendererMediaPlayerManagerEfl::~RendererMediaPlayerManagerEfl() { + DCHECK(media_players_.empty()) + << "RendererMediaPlayerManagerEfl is owned by RenderFrameImpl and is " + "destroyed only after all media players are destroyed."; +} + +void RendererMediaPlayerManagerEfl::PausePlayingPlayers() { + std::map::iterator player_it; + for (player_it = media_players_.begin();player_it != media_players_.end();) { + media::WebMediaPlayerEfl* player = player_it->second; + // Element pointed by the iterator can get deleted during the function call + // "player->RequestPause()", hence increment the iterator beforehand + ++player_it; + if (player && !player->paused() && player->hasVideo()) + player->RequestPause(); + } +} + +bool RendererMediaPlayerManagerEfl::OnMessageReceived( + const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(RendererMediaPlayerManagerEfl, message) + IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_MediaDataChanged, OnMediaDataChange) + IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_DurationChanged, OnDurationChange) + IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_TimeUpdate, OnTimeUpdate) + IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_BufferUpdate, OnBufferUpdate) + IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_ReadyStateChange, OnReadyStateChange) + IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_NetworkStateChange, + OnNetworkStateChange) + IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_TimeChanged, OnTimeChanged) + IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_OnPauseStateChange, + OnPauseStateChange) + IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_OnSeekStateChange, OnSeekStateChange) + IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_SeekRequest, OnRequestSeek) + IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_NewFrameAvailable, + OnNewFrameAvailable) +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_PlatformSurfaceUpdated, + OnPlatformSurfaceUpdated) +#endif + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void RendererMediaPlayerManagerEfl::Initialize( + int player_id, + MediaPlayerHostMsg_Initialize_Type type, + const GURL& url, + double volume, + int demuxer_client_id) { + Send(new MediaPlayerGstHostMsg_Init( + routing_id(), player_id, type, url, volume, demuxer_client_id)); +} + +void RendererMediaPlayerManagerEfl::OnMediaDataChange( + int player_id, + int format, + int height, + int width, + int media) { + media::WebMediaPlayerEfl* player = GetMediaPlayer(player_id); + if (player) + player->OnMediaDataChange(format, height, width, media); +} + +void RendererMediaPlayerManagerEfl::OnDurationChange( + int player_id, + double duration) { + media::WebMediaPlayerEfl* player = GetMediaPlayer(player_id); + if (player) + player->OnDurationChange(duration); +} + +void RendererMediaPlayerManagerEfl::OnTimeUpdate( + int player_id, + double current_time) { + media::WebMediaPlayerEfl* player = GetMediaPlayer(player_id); + if (player) + player->OnTimeUpdate(current_time); +} + +void RendererMediaPlayerManagerEfl::OnBufferUpdate( + int player_id, + std::vector buffer_range) { + media::WebMediaPlayerEfl* player = GetMediaPlayer(player_id); + if (player) + player->OnBufferUpdate(buffer_range); +} + +void RendererMediaPlayerManagerEfl::OnReadyStateChange( + int player_id, + media::MediaPlayerEfl::ReadyState state) { + media::WebMediaPlayerEfl* player = GetMediaPlayer(player_id); + if (player) + player->SetReadyState( + static_cast(state)); +} + +void RendererMediaPlayerManagerEfl::OnNetworkStateChange( + int player_id, + media::MediaPlayerEfl::NetworkState state) { + media::WebMediaPlayerEfl* player = GetMediaPlayer(player_id); + if (player) + player->SetNetworkState( + static_cast(state)); +} + +void RendererMediaPlayerManagerEfl::OnTimeChanged(int player_id) { + media::WebMediaPlayerEfl* player = GetMediaPlayer(player_id); + if (player) + player->OnTimeChanged(); +} + +void RendererMediaPlayerManagerEfl::OnPauseStateChange( + int player_id, + bool state) { + media::WebMediaPlayerEfl* player = GetMediaPlayer(player_id); + if (player) + player->OnPauseStateChange(state); +} + +void RendererMediaPlayerManagerEfl::OnSeekStateChange( + int player_id, + bool state) { + media::WebMediaPlayerEfl* player = GetMediaPlayer(player_id); + if (player) + player->OnSeekStateChange(state); +} + +void RendererMediaPlayerManagerEfl::OnRequestSeek( + int player_id, + double seek_time) { + media::WebMediaPlayerEfl* player = GetMediaPlayer(player_id); + if (player) + player->OnRequestSeek(seek_time); +} + +void RendererMediaPlayerManagerEfl::OnNewFrameAvailable( + int player_id, + base::SharedMemoryHandle foreign_memory_handle, + uint32 length, base::TimeDelta timestamp) { + media::WebMediaPlayerEfl* player = GetMediaPlayer(player_id); + // FIXME: Handle exception for all APIs. + if (player) + player->OnNewFrameAvailable(foreign_memory_handle, length, timestamp); +} + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +void RendererMediaPlayerManagerEfl::OnPlatformSurfaceUpdated( + int player_id, + int pixmap_id, + base::TimeDelta timestamp) { + media::WebMediaPlayerEfl* player = GetMediaPlayer(player_id); + if (player) + player->OnPlatformSurfaceUpdated(pixmap_id, timestamp); +} +#endif + +media::WebMediaPlayerEfl* RendererMediaPlayerManagerEfl::GetMediaPlayer( + int player_id) { + std::map::iterator iter = + media_players_.find(player_id); + if (iter != media_players_.end()) + return iter->second; + + return NULL; +} + +void RendererMediaPlayerManagerEfl::Play(int player_id) { + Send(new MediaPlayerGstHostMsg_Play(routing_id(), player_id)); +} + +void RendererMediaPlayerManagerEfl::Pause( + int player_id, + bool is_media_related_action) { + Send(new MediaPlayerGstHostMsg_Pause(routing_id(), player_id)); +} + +void RendererMediaPlayerManagerEfl::Seek(int player_id, double time) { + Send(new MediaPlayerGstHostMsg_Seek(routing_id(), player_id, time)); +} + +void RendererMediaPlayerManagerEfl::SetVolume(int player_id, double volume) { + Send(new MediaPlayerGstHostMsg_SetVolume(routing_id(), player_id, volume)); +} + +void RendererMediaPlayerManagerEfl::SetRate(int player_id, double rate) { + Send(new MediaPlayerGstHostMsg_SetRate(routing_id(), player_id, rate)); +} + +void RendererMediaPlayerManagerEfl::DestroyPlayer(int player_id) { + VLOG(1) << "RendererMediaPlayerManagerEfl::" << __FUNCTION__ + << " Plyer-Id = " << player_id; + Send(new MediaPlayerGstHostMsg_DeInit(routing_id(), player_id)); +} + +int RendererMediaPlayerManagerEfl::RegisterMediaPlayer( + media::WebMediaPlayerEfl* player) { + media_players_[next_media_player_id_] = player; + return next_media_player_id_++; +} + +void RendererMediaPlayerManagerEfl::UnregisterMediaPlayer(int player_id) { + VLOG(1) << "RendererMediaPlayerManagerEfl::" << __FUNCTION__ + << " Player-Id = " << player_id; + media_players_.erase(player_id); +} + +} // namespace content diff --git a/tizen_src/chromium_impl/content/renderer/media/efl/renderer_media_player_manager_efl.h b/tizen_src/chromium_impl/content/renderer/media/efl/renderer_media_player_manager_efl.h new file mode 100644 index 000000000000..7459902a0574 --- /dev/null +++ b/tizen_src/chromium_impl/content/renderer/media/efl/renderer_media_player_manager_efl.h @@ -0,0 +1,111 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_RENDERER_MEDIA_TIZEN_RENDERER_MEDIA_PLAYER_TIZEN_MANAGER_H_ +#define CONTENT_RENDERER_MEDIA_TIZEN_RENDERER_MEDIA_PLAYER_TIZEN_MANAGER_H_ + +#include "content/public/renderer/render_frame_observer.h" +#include "media/base/efl/media_player_efl.h" +#include "media/base/efl/webmediaplayer_efl.h" +#include "url/gurl.h" + +namespace media { +class WebMediaPlayerEfl; +} + +namespace content { + +class RendererMediaPlayerManagerEfl : public RenderFrameObserver { + public: + // Constructs a RendererMediaPlayerManagerEfl object for the |render_frame|. + explicit RendererMediaPlayerManagerEfl(RenderFrame* render_frame); + virtual ~RendererMediaPlayerManagerEfl(); + + // Initializes a MediaPlayerEfl object in browser process. + void Initialize( + int player_id, + MediaPlayerHostMsg_Initialize_Type type, + const GURL& url, + double volume, + int demuxer_client_id); + + // Starts the player. + void Play(int player_id); + + // Pauses the player. + // is_media_related_action should be true if this pause is coming from an + // an action that explicitly pauses the video (user pressing pause, JS, etc.) + // Otherwise it should be false if Pause is being called due to other reasons + // (cleanup, freeing resources, etc.) + void Pause(int player_id, bool is_media_related_action); + + // Performs seek on the player. + void Seek(int player_id, double time); + + // Sets the player volume. + void SetVolume(int player_id, double volume); + + // Sets the playback rate. + void SetRate(int player_id, double rate); + + // Destroys the player in the browser process + void DestroyPlayer(int player_id); + + // Registers and unregisters a WebMediaPlayerEfl object. + int RegisterMediaPlayer(media::WebMediaPlayerEfl* player); + void UnregisterMediaPlayer(int player_id); + + bool OnMessageReceived(const IPC::Message& message) override; + + media::WebMediaPlayerEfl* GetMediaPlayer(int player_id); + + //Pause the playing media players when tab/webpage goes to background + void PausePlayingPlayers(); + + private: + void OnNewFrameAvailable( + int player_id, + base::SharedMemoryHandle foreign_memory_handle, + uint32 length, base::TimeDelta timestamp); + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + void OnPlatformSurfaceUpdated( + int player_id, + int pixmap_id, + base::TimeDelta timestamp); +#endif + + void OnMediaDataChange( + int player_id, + int format, + int height, + int width, + int media); + void OnDurationChange(int player_id, double duration); + void OnTimeUpdate(int player_id, double current_time); + void OnBufferUpdate( + int player_id, + std::vector buffer_range); + void OnTimeChanged(int player_id); + void OnPauseStateChange(int player_id, bool state); + void OnSeekStateChange(int player_id, bool state); + void OnRequestSeek(int player_id, double seek_time); + void OnReadyStateChange( + int player_id, + media::MediaPlayerEfl::ReadyState state ); + void OnNetworkStateChange( + int player_id, + media::MediaPlayerEfl::NetworkState state ); + + private: + std::map media_players_; + + int next_media_player_id_; + + DISALLOW_COPY_AND_ASSIGN(RendererMediaPlayerManagerEfl); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_MEDIA_TIZEN_RENDERER_MEDIA_PLAYER_TIZEN_MANAGER_H_ diff --git a/tizen_src/chromium_impl/content/renderer/print_pages_params.cc b/tizen_src/chromium_impl/content/renderer/print_pages_params.cc new file mode 100644 index 000000000000..6635ad1fe25e --- /dev/null +++ b/tizen_src/chromium_impl/content/renderer/print_pages_params.cc @@ -0,0 +1,28 @@ +// Copyright 2014 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/renderer/print_pages_params.h" + +namespace content { + +PrintParams::PrintParams() + : page_size(), + content_size(), + printable_area(), + dpi(0), + desired_dpi(0), + is_first_request(true), + print_to_pdf(true), + print_scaling_option(blink::WebPrintScalingOptionSourceSize), + document_cookie(0) { +} + +PrintPagesParams::PrintPagesParams() + : pages() { +} + +PrintPagesParams::~PrintPagesParams(){ +} + +} // namespace content diff --git a/tizen_src/chromium_impl/content/renderer/print_pages_params.h b/tizen_src/chromium_impl/content/renderer/print_pages_params.h new file mode 100644 index 000000000000..5f0a7701932b --- /dev/null +++ b/tizen_src/chromium_impl/content/renderer/print_pages_params.h @@ -0,0 +1,58 @@ +// Copyright 2014 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PRINT_PAGES_PARAMS_H_ +#define PRINT_PAGES_PARAMS_H_ + +#include + +#include "base/basictypes.h" +#include "base/files/file_path.h" +#include "base/memory/shared_memory.h" +#include "printing/printing_export.h" +#include "third_party/WebKit/public/web/WebPrintScalingOption.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/size.h" + +namespace content { + +struct PrintParams { + PrintParams(); + + gfx::Size page_size; + gfx::Size content_size; + gfx::Rect printable_area; + double dpi; + int desired_dpi; + bool is_first_request; + bool print_to_pdf; + blink::WebPrintScalingOption print_scaling_option; + int document_cookie; +}; + +// collection of printable pages +struct PrintPagesParams { + PrintPagesParams(); + ~PrintPagesParams(); + + PrintParams params; + std::vector pages; +}; + +// single page +struct PrintPageParams { + PrintParams params; + int page_number; +}; + +struct DidPrintPagesParams { + base::SharedMemoryHandle metafile_data_handle; + uint32 data_size; + int document_cookie; + base::FilePath filename; +}; + +} // namespace content + +#endif // PRINT_PAGES_PARAMS_H_ diff --git a/tizen_src/chromium_impl/media/audio/tizen/audio_session_manager.cc b/tizen_src/chromium_impl/media/audio/tizen/audio_session_manager.cc new file mode 100644 index 000000000000..b308e66178a0 --- /dev/null +++ b/tizen_src/chromium_impl/media/audio/tizen/audio_session_manager.cc @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2014 Samsung Electronics. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "media/audio/tizen/audio_session_manager.h" + +#include +#include +#include +#include + +#include "base/logging.h" +#include "config.h" + +namespace media { + +AudioSessionManager::AudioSessionManager() + : m_eventType_(ASM_EVENT_NONE) + , m_handle_(-1) + , m_notifyCallback_(0) + , m_processIdentifier_(getpid()) + , m_sessionType_(MM_SESSION_TYPE_NUM) + , m_stateType_(ASM_STATE_NONE) + , m_allocated_(false) + , m_resources_() { +} + +AudioSessionManager::~AudioSessionManager() { + if (m_allocated_) + DeallocateResources(); + + UnregisterAudioSessionManager(); +} + +bool AudioSessionManager::RegisterAudioSessionManager( + MMSessionType sessiontype, + ASM_sound_cb_t notifyCallback, + void* callbackData) { + int error = _mm_session_util_read_type + (m_processIdentifier_, reinterpret_cast(&m_sessionType_)); + if (error) { + m_sessionType_ = sessiontype; + error = mm_session_init((int)m_sessionType_); + if (error) { + LOG(ERROR) << "mm_session_init() failed."; + return false; + } + } + m_eventType_ = InterpretSessionToEvent(m_sessionType_); + m_notifyCallback_ = notifyCallback; + if (!ASM_register_sound + (m_processIdentifier_, &m_handle_, m_eventType_, m_stateType_, + m_notifyCallback_, callbackData, ASM_RESOURCE_NONE, &error)) { + LOG(ERROR) << "register is failed. errcode = " << error; + return false; + } + return true; +} + +bool AudioSessionManager::UnregisterAudioSessionManager() { + int error = 0; + if (!ASM_unregister_sound(m_handle_, m_eventType_, &error)) { + LOG(ERROR) << "unregister is failed. errcode = " << error; + return false; + } + return true; +} + +int AudioSessionManager::GetSoundState(ASM_sound_states_t* state) { + int error = 0; + if (!ASM_get_sound_state( m_handle_, m_eventType_, state, &error)) + LOG(ERROR) << "getSoundState is failed. errcode = " << error; + return error; +} + +bool AudioSessionManager::SetSoundState(ASM_sound_states_t state) { + int error = 0; + if (!ASM_set_sound_state( + m_handle_, m_eventType_, state, ASM_RESOURCE_NONE, &error)) { + LOG(ERROR) << "setSoundState is failed. errcode = " << error; + return false; + } + return true; +} + +ASM_sound_events_t AudioSessionManager::InterpretSessionToEvent( + MMSessionType sessionType) { + switch (sessionType) { + case MM_SESSION_TYPE_SHARE: + return ASM_EVENT_SHARE_MMPLAYER; + case MM_SESSION_TYPE_EXCLUSIVE: + return ASM_EVENT_EXCLUSIVE_MMPLAYER; + default: + return ASM_EVENT_NONE; + } +} + +bool AudioSessionManager::AllocateResources(GstElement* element) { + GList* list = NULL; + gst_element_query_resource(element, &list); + + ASM_request_resources_t toAllocate; + toAllocate.requested_resources_num = 0; + int i = 0; + for (GList* resource(list); resource; resource = resource->next) { + toAllocate.device_category[toAllocate.requested_resources_num] + = static_cast(GPOINTER_TO_INT(resource->data)); + toAllocate.access_right[toAllocate.requested_resources_num] + = ASM_RESOURCE_ACCESS_RIGHT_EXCLUSIVE; + + ++toAllocate.requested_resources_num; + } + g_list_free(list); + + if (!toAllocate.requested_resources_num) { + LOG(ERROR) << "No resources requested by : " << GST_ELEMENT_NAME(element); + return true; + } + + if (MAX_RESOURCE_NUM < toAllocate.requested_resources_num + + m_resources_.requested_resources_num) { + toAllocate.requested_resources_num = 0; + return false; + } + + int error(0); + ASM_allocate_resources(m_handle_, &toAllocate, false, &error); + if (error) { + LOG(ERROR) << "Error allocating ASM resource. errcode : " << error; + return false; + } + + // Register this resources as allocated for future deallocation + for (int i = 0; i < toAllocate.requested_resources_num; ++i) { + m_resources_.device_id[m_resources_.requested_resources_num] + = toAllocate.device_id[i]; + m_resources_.device_category[m_resources_.requested_resources_num] + = toAllocate.device_category[i]; + m_resources_.access_right[m_resources_.requested_resources_num] + = toAllocate.access_right[i]; + ++m_resources_.requested_resources_num; + } + m_allocated_ = true; + return true; +} + +bool AudioSessionManager::DeallocateResources() { + // No good rollback from failure during resource deallocation. + // The only smart move in this case would be to kill process, + // but do we really want to do it? + // Hence we ignore possible errors during resource deallocation. + int error(0); + m_allocated_ = !ASM_deallocate_resources(m_handle_, &m_resources_, &error); + if (error) + LOG(ERROR) << "Error deallocating ASM resources. errcode : " << error; + m_resources_.requested_resources_num = 0; + return !m_allocated_; +} + +} diff --git a/tizen_src/chromium_impl/media/audio/tizen/audio_session_manager.h b/tizen_src/chromium_impl/media/audio/tizen/audio_session_manager.h new file mode 100644 index 000000000000..9b88505ac191 --- /dev/null +++ b/tizen_src/chromium_impl/media/audio/tizen/audio_session_manager.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2014 Samsung Electronics. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AUDIO_SESSION_MANAGER_H_ +#define AUDIO_SESSION_MANAGER_H_ + +#include +#include +#include +#include + +#include "base/memory/ref_counted.h" + +namespace media { + +class AudioSessionManager : public base::RefCounted { +public: + static scoped_refptr CreateAudioSessionManager() { + return make_scoped_refptr(new AudioSessionManager()); + } + + static void SetVolumeSessionToMediaType(); + static void ClearVolumeSessionFromMediaType(); + + virtual ~AudioSessionManager(); + + bool RegisterAudioSessionManager(MMSessionType, ASM_sound_cb_t, void*); + bool UnregisterAudioSessionManager(); + + int GetSoundState(ASM_sound_states_t*); + bool SetSoundState(ASM_sound_states_t); + ASM_sound_events_t InterpretSessionToEvent(MMSessionType); + bool AllocateResources(GstElement*); + bool DeallocateResources(); + + bool IsEmpty() const; + +private: + AudioSessionManager(); + + ASM_sound_cb_t m_notifyCallback_; + ASM_sound_events_t m_eventType_; + ASM_sound_states_t m_stateType_; + ASM_request_resources_t m_resources_; + + MMSessionType m_sessionType_; + + bool m_allocated_; + int m_handle_; + int m_processIdentifier_; +}; +} +#endif diff --git a/tizen_src/chromium_impl/media/base/efl/demuxer_efl.h b/tizen_src/chromium_impl/media/base/efl/demuxer_efl.h new file mode 100644 index 000000000000..bb219fed5c3c --- /dev/null +++ b/tizen_src/chromium_impl/media/base/efl/demuxer_efl.h @@ -0,0 +1,61 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_BASE_TIZEN_DEMUXER_TIZEN_H_ +#define MEDIA_BASE_TIZEN_DEMUXER_TIZEN_H_ + +#include "media/base/efl/demuxer_stream_player_params_efl.h" + +namespace media { + +// Defines the client callback interface. +class MEDIA_EXPORT DemuxerEflClient { + public: + + // Called in response to RequestDemuxerConfigs() and also when the demuxer + // has initialized. + virtual void OnDemuxerConfigsAvailable(const DemuxerConfigs& params) = 0; + + // Called in response to RequestDemuxerData(). + virtual void OnDemuxerDataAvailable( + base::SharedMemoryHandle foreign_memory_handle, + const media::DemuxedBufferMetaData& meta_data) = 0; + + // Called in response to RequestDemuxerData() when no data is available. + virtual void OnBufferMetaDataAvailable( + const media::DemuxedBufferMetaData& meta_data) = 0; + + // Called to inform demuxer seek completion. + virtual void OnDemuxerSeekDone( + const base::TimeDelta& actual_browser_seek_time) = 0; + + // Called whenever the demuxer has detected a duration change. + virtual void OnDemuxerDurationChanged(base::TimeDelta duration) = 0; + + protected: + virtual ~DemuxerEflClient() {} +}; + +// Defines a demuxer with asynchronous operations. +class MEDIA_EXPORT DemuxerEfl { + public: + virtual ~DemuxerEfl() {} + + // Initializes this demuxer with |client| as the callback handler. + // Must be called prior to calling any other methods. + virtual void Initialize(DemuxerEflClient* client) = 0; + + // Called to request the current audio/video decoder configurations. + virtual void RequestDemuxerConfigs() = 0; + + // Called to request demuxer seek. + virtual void RequestDemuxerSeek(const base::TimeDelta& time_to_seek) = 0; + + // Called to request additional data from the demuxer. + virtual void RequestDemuxerData(media::DemuxerStream::Type type) = 0; +}; + +} // namespace media + +#endif // MEDIA_BASE_TIZEN_DEMUXER_TIZEN_H_ diff --git a/tizen_src/chromium_impl/media/base/efl/demuxer_stream_player_params_efl.cc b/tizen_src/chromium_impl/media/base/efl/demuxer_stream_player_params_efl.cc new file mode 100644 index 000000000000..3e90f6505634 --- /dev/null +++ b/tizen_src/chromium_impl/media/base/efl/demuxer_stream_player_params_efl.cc @@ -0,0 +1,28 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/base/efl/demuxer_stream_player_params_efl.h" + +namespace media { + +DemuxerConfigs::DemuxerConfigs() + : audio_codec(kUnknownAudioCodec), + audio_channels(0), + audio_sampling_rate(0), + is_audio_encrypted(false), + video_codec(kUnknownVideoCodec), + is_video_encrypted(false), + duration_ms(0) {} + +DemuxerConfigs::~DemuxerConfigs() {} + +DemuxedBufferMetaData::DemuxedBufferMetaData() + : size(0), + end_of_stream(false), + type(DemuxerStream::UNKNOWN), + status(DemuxerStream::kAborted) {} + +DemuxedBufferMetaData::~DemuxedBufferMetaData() {} + +} // namespace media diff --git a/tizen_src/chromium_impl/media/base/efl/demuxer_stream_player_params_efl.h b/tizen_src/chromium_impl/media/base/efl/demuxer_stream_player_params_efl.h new file mode 100644 index 000000000000..a9936fa9cd34 --- /dev/null +++ b/tizen_src/chromium_impl/media/base/efl/demuxer_stream_player_params_efl.h @@ -0,0 +1,51 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_BASE_TIZEN_DEMUXER_STREAM_PLAYER_PARAMS_EFL_H_ +#define MEDIA_BASE_TIZEN_DEMUXER_STREAM_PLAYER_PARAMS_EFL_H_ + +#include + +#include "media/base/audio_decoder_config.h" +#include "media/base/decrypt_config.h" +#include "media/base/demuxer_stream.h" +#include "media/base/media_export.h" +#include "media/base/video_decoder_config.h" +#include "ui/gfx/size.h" + +namespace media { + +struct MEDIA_EXPORT DemuxerConfigs { + DemuxerConfigs(); + ~DemuxerConfigs(); + + AudioCodec audio_codec; + int audio_channels; + int audio_sampling_rate; + bool is_audio_encrypted; + std::vector audio_extra_data; + + VideoCodec video_codec; + gfx::Size video_size; + bool is_video_encrypted; + std::vector video_extra_data; + + int duration_ms; +}; + +struct MEDIA_EXPORT DemuxedBufferMetaData { + DemuxedBufferMetaData(); + ~DemuxedBufferMetaData(); + + int size; + bool end_of_stream; + base::TimeDelta timestamp; + base::TimeDelta time_duration; + DemuxerStream::Type type; + DemuxerStream::Status status; +}; + +}; // namespace media + +#endif // MEDIA_BASE_TIZEN_DEMUXER_STREAM_PLAYER_PARAMS_TIZEN_H_ diff --git a/tizen_src/chromium_impl/media/base/efl/media_player_bridge_gstreamer.cc b/tizen_src/chromium_impl/media/base/efl/media_player_bridge_gstreamer.cc new file mode 100644 index 000000000000..a0f2b00caa85 --- /dev/null +++ b/tizen_src/chromium_impl/media/base/efl/media_player_bridge_gstreamer.cc @@ -0,0 +1,1256 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/base/efl/media_player_bridge_gstreamer.h" + +#include +#include +#include +#include + +#include "base/basictypes.h" +#include "base/message_loop/message_loop_proxy.h" +#include "media/base/efl/media_player_manager_efl.h" +#include "ui/gfx/size.h" + +#if defined(OS_TIZEN_MOBILE) && (defined(TIZEN_V_2_3) || defined(TIZEN_V_2_4)) +#include +#endif + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +#if GST_VERSION_MAJOR == 1 +#include +#else +#include +#endif +#endif + +namespace { + +// fourcc for gst-video-format +const uint32 GST_VIDEO_SN12 = GST_MAKE_FOURCC('S','N','1','2'); + +// tile size for SN12 +const uint SN12_TILE_WIDTH = 64; +const uint SN12_TILE_HEIGHT = 32; +const uint SN12_TILE_SIZE = SN12_TILE_WIDTH * SN12_TILE_HEIGHT; + +// GstPlayFlags in |gstplay-enum.h| +typedef enum { + GST_PLAY_FLAG_VIDEO = (1 << 0), + GST_PLAY_FLAG_AUDIO = (1 << 1), + GST_PLAY_FLAG_TEXT = (1 << 2), + GST_PLAY_FLAG_VIS = (1 << 3), + GST_PLAY_FLAG_SOFT_VOLUME = (1 << 4), + GST_PLAY_FLAG_NATIVE_AUDIO = (1 << 5), + GST_PLAY_FLAG_NATIVE_VIDEO = (1 << 6), + GST_PLAY_FLAG_DOWNLOAD = (1 << 7), + GST_PLAY_FLAG_BUFFERING = (1 << 8), + GST_PLAY_FLAG_DEINTERLACE = (1 << 9), + GST_PLAY_FLAG_SOFT_COLORBALANCE = (1 << 10) +} GstPlayFlags; + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +typedef enum { + DEGREE_0, // No rotate + DEGREE_90, // Rotate 90 degree count clockwise + DEGREE_180, // Rotate 180 degree count clockwise + DEGREE_270 // Rotate 270 degree count clockwise +} RotateAngle; +#endif + +// Playbin element name +const char* kPlaybinName = "gst_playbin"; +const char* kVideoSink = "gst_video_sink"; +const char* kPropertyBufferSize = "buffer-size"; +const char* kPropertyMaxBuffers = "max-buffers"; +const char* kPropertyVolume = "volume"; +const char* kPropertyUri = "uri"; +const char* kPropertyAudioStream = "n-audio"; +const char* kPropertyVideoStream = "n-video"; +const char* kPropertyTextStream = "n-text"; + +// Update duration every 100ms. +const int kDurationUpdateInterval = 100; +const int kMaxBuffer = 1; + +// sample size for audio/video buffering +const int kPreloadBufferSize = (3 * 1024 * 1024); // 3MB + +const GstClockTime ConvertToGstClockTime(double time) { + if (time < 0) { + LOG(ERROR) << "Invalid time:" << time << " Reset to 0"; + time = 0; + } + + // Extract the integer part of the time (seconds) and the fractional part + // (microseconds). Attempt to round the microseconds so no floating point + // precision is lost and we can perform an accurate seek. + double seconds = 0; + double microSeconds = std::modf(time, &seconds) * 1000000; + GTimeVal timeValue; + timeValue.tv_sec = static_cast(seconds); + timeValue.tv_usec = static_cast(lround(microSeconds / 10) * 10); + return GST_TIMEVAL_TO_TIME(timeValue); +} + +const double ConvertNanoSecondsToSeconds(int64 time) { + double seconds = static_cast(time) / + (base::Time::kNanosecondsPerSecond); + return seconds; +} + +} // namespace + +namespace media { + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +static Eina_Bool notify_damage_updated_cb(void* data, int type, void* event) { + MediaPlayerBridgeGstreamer* player = + static_cast (data); + if (!player) + return ECORE_CALLBACK_PASS_ON; + + player->PlatformSurfaceUpdated(); + return ECORE_CALLBACK_PASS_ON; +} + +static int get_pixmap_id_cb(void* data) { + MediaPlayerBridgeGstreamer* player = + static_cast (data); + return player->GetSurfaceID(); +} +#endif + +static GstBusSyncReply gst_pipeline_message_cb( + GstBus* bus, + GstMessage* message, + gpointer user_data) { + MediaPlayerBridgeGstreamer* player = + static_cast(user_data); + if (!player) + return GST_BUS_PASS; + + player->HandleMessage(message); + gst_message_unref(message); + return GST_BUS_DROP; +} + +static void on_gst_appsink_eos( + GstAppSink* appsink, + gpointer user_data) { + // EOS is Handled in state handling. Do nothing. +} + +// Audio part of GStreamer is not yet implemented. Workaround to handle +// |PREROLLED| for audio files is to update based on |GST_MESSAGE_BUFFERING|. +static GstFlowReturn on_gst_appsink_preroll( + GstAppSink* sink, + gpointer user_data) { + MediaPlayerBridgeGstreamer* player = + static_cast(user_data); + if (!player) + return GST_FLOW_ERROR; + player->PrerollComplete(); + return GST_FLOW_OK; +} + +static GstFlowReturn on_gst_appsink_sample( + GstAppSink* sink, + gpointer user_data) { + MediaPlayerBridgeGstreamer* player = + static_cast(user_data); + if (!player) + return GST_FLOW_ERROR; + + player->SampleReady(player->PullSample()); + return GST_FLOW_OK; +} + +static void on_gst_installer_result_function( + GstInstallPluginsReturn result, + gpointer userData) { + MediaPlayerBridgeGstreamer* player = + reinterpret_cast(userData); + player->HandlePluginInstallerResult(result); +} + +MediaPlayerBridgeGstreamer::MediaPlayerBridgeGstreamer( + int player_id, + const GURL& url, + double volume, + MediaPlayerManager* manager_in) + : MediaPlayerEfl(player_id, manager_in), + main_loop_(base::MessageLoopProxy::current()), + gst_playbin_(NULL), + gst_appsink_(NULL), + url_(url), + volume_(volume), + gst_width_(0), + gst_height_(0), + is_prerolled_(false), + is_paused_(true), + duration_(0), + playback_rate_(1.0f), + buffered_(0), + video_format_(0), + media_type_(0), + is_live_stream_(false), + is_file_url_(false), + is_end_reached_(false), + is_seeking_(false), + is_seek_pending_(false), + seek_duration_(0), + error_occured_(false), + missing_plugins_(false), + is_pixmap_used_(false), +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + pixmap_id_(0), + efl_pixmap_(NULL), + m_damage(0), + m_damageHandler(NULL), +#endif + bufsize_sn12_(0), + shared_memory_size(0) { + LOG(INFO) << "MediaPlayerBridgeGstreamer - URL = " << url_.spec().c_str(); + + // gstreamer port + if (!gst_is_initialized()) { + gst_init_check(NULL, NULL, 0); + } + + if (gst_is_initialized()) { +#if GST_VERSION_MAJOR == 1 + gst_playbin_ = gst_element_factory_make("playbin", kPlaybinName); +#else + gst_playbin_ = gst_element_factory_make("playbin2", kPlaybinName); +#endif + gst_appsink_ = GetVideoSink(); + if (gst_playbin_ && gst_appsink_) { + g_object_set(gst_playbin_, "video-sink", gst_appsink_, NULL); + + // QoS property will enable the quality-of-service features of the + // basesink which gather statistics about the real-time performance + // of the clock synchronisation. For each sample received in the sink, + // statistics are gathered and a QOS event is sent upstream with + // these numbers. This information can then be used by upstream + // elements to reduce their processing rate, for example. + if(!gst_base_sink_is_qos_enabled(GST_BASE_SINK(gst_appsink_))) + gst_base_sink_set_qos_enabled(GST_BASE_SINK(gst_appsink_), true); + + GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(gst_playbin_)); + if (!bus) { + LOG(ERROR) << "GStreamer bus creation failed"; + HandleError(MediaPlayerEfl::NetworkStateDecodeError); + return; + } +#if GST_VERSION_MAJOR == 1 + gst_bus_set_sync_handler( + bus, (GstBusSyncHandler)gst_pipeline_message_cb, this, NULL); +#else + gst_bus_set_sync_handler( + bus, (GstBusSyncHandler)gst_pipeline_message_cb, this); +#endif + gst_object_unref (bus); + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + PrepareForVideoSink(); +#else + PrepareForVideoFrame(); +#endif + + g_object_set(G_OBJECT(gst_playbin_), kPropertyVolume, volume_, NULL); + g_object_set( + G_OBJECT(gst_playbin_), kPropertyUri, url_.spec().c_str(), NULL); + + if (gst_element_set_state( + gst_playbin_, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) + LOG(ERROR) << "GStreamer state change failed"; + + manager()->OnReadyStateChange( + GetPlayerId(), MediaPlayerEfl::ReadyStateHaveEnoughData); + manager()->OnNetworkStateChange( + GetPlayerId(), MediaPlayerEfl::NetworkStateLoaded); + + if(url_.SchemeIsFile()) + is_file_url_ = true; + } else { + if (gst_playbin_) { + gst_object_unref(gst_playbin_); + gst_playbin_ = NULL; + } + if(gst_appsink_) { + gst_object_unref(gst_appsink_); + gst_appsink_ = NULL; + } + LOG(ERROR) << "Unable to create GStreamer elements"; + HandleError(MediaPlayerEfl::NetworkStateDecodeError); + } + } else { + LOG(ERROR) << "Unable to initialize GST"; + HandleError(MediaPlayerEfl::NetworkStateDecodeError); + } +} + +MediaPlayerBridgeGstreamer::~MediaPlayerBridgeGstreamer() { + VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); +} + +void MediaPlayerBridgeGstreamer::Destroy() { + VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); + if (IsPlayerDestructing()) + return; + + destructing_ = true; + Release(); + main_loop_->DeleteSoon(FROM_HERE, this); +} + +void MediaPlayerBridgeGstreamer::Play() { + VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); + if (!gst_playbin_) + return; + if (error_occured_ || is_end_reached_) + return; + if (playback_rate_ == 0.0) { + is_paused_ = false; + return; + } + if (gst_element_set_state( + gst_playbin_, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { + LOG(ERROR) << "GStreamer state change failed in PLAY"; + return; + } + +#if defined(OS_TIZEN_MOBILE) && (defined(TIZEN_V_2_3) || defined(TIZEN_V_2_4)) + if (device_power_request_lock(POWER_LOCK_DISPLAY, 0) != DEVICE_ERROR_NONE) + LOG(ERROR) << "|device_power_request_lock| request failed"; +#endif + + StartCurrentTimeUpdateTimer(); + is_paused_ = false; + is_end_reached_ = false; +} + +void MediaPlayerBridgeGstreamer::Pause(bool is_media_related_action) { + VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); + if (!gst_playbin_) + return; + if (error_occured_) + return; + if (gst_element_set_state( + gst_playbin_, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) { + LOG(ERROR) << "GStreamer state change failed in PAUSE"; + return; + } + +#if defined(OS_TIZEN_MOBILE) && (defined(TIZEN_V_2_3) || defined(TIZEN_V_2_4)) + if (device_power_release_lock(POWER_LOCK_DISPLAY) != DEVICE_ERROR_NONE) + LOG(ERROR) << "|device_power_release_lock| request failed"; +#endif + + StopCurrentTimeUpdateTimer(); + is_paused_ = true; +} + +void MediaPlayerBridgeGstreamer::SetRate(double rate) { + VLOG(1) << __FUNCTION__ << "Rate (" << rate << ")"; + if (!gst_playbin_) + return; + if (error_occured_) + return; + if (playback_rate_ == rate) + return; + if (is_live_stream_) + return; + + GstState state = GST_STATE_NULL; + GstState pending = GST_STATE_NULL; + gst_element_get_state(gst_playbin_, &state, &pending, 0); + if ((state != GST_STATE_PLAYING && state != GST_STATE_PAUSED) + || (pending == GST_STATE_PAUSED)) + return; + if (rate == 0.0) { + playback_rate_ = rate; + Pause(true); + return; + } + + // If rate was zero and requested rate is non-zero, change the paused state + if(playback_rate_ == 0.0 && rate != 0.0) { + Play(); + StartCurrentTimeUpdateTimer(); + } + + double current_position = GetCurrentTime() * GST_SECOND; + + if (rate < 0 && current_position == 0.0f) + current_position = -1.0f; + if (SeekTo( + current_position, rate, + static_cast(GST_SEEK_FLAG_FLUSH))) { + + // FIXME: Is is required to mute at abnormal playback rate? + playback_rate_ = rate; + } else { + LOG(ERROR) << "Setting Rate " << rate << " failed"; + HandleError(MediaPlayerEfl::NetworkStateDecodeError); + } +} + +void MediaPlayerBridgeGstreamer::Seek(const double time) { + VLOG(1) << __FUNCTION__ << "Time (" << time<< ")"; + + if (IsPlayerDestructing()) + return; + + if (!gst_playbin_ || error_occured_ || is_live_stream_ || + time == GetCurrentTime()) { + main_loop_->PostTask(FROM_HERE, base::Bind( + &MediaPlayerBridgeGstreamer::OnTimeChanged, base::Unretained(this))); + return; + } + + GstState state = GST_STATE_NULL; + GstStateChangeReturn ret = gst_element_get_state( + gst_playbin_, &state, NULL, 250 * GST_NSECOND); + if (ret == GST_STATE_CHANGE_FAILURE || ret == GST_STATE_CHANGE_NO_PREROLL) { + LOG(ERROR) << "Cannot seek in " + << gst_element_state_change_return_get_name(ret) << " state"; + return; + } + + StopCurrentTimeUpdateTimer(); + if (SeekTo( + ConvertToGstClockTime(time), playback_rate_, static_cast + (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE))) { + UpdateSeekState(true); + seek_duration_ = time; + is_end_reached_ = time != duration_ ? false : true; + manager()->OnTimeUpdate(GetPlayerId(), time); + if (!is_paused_) + StartCurrentTimeUpdateTimer(); + } else { + LOG(ERROR) << "MediaPlayerBridgeGstreamer::" << __FUNCTION__<<": Failed!"; + manager()->OnTimeUpdate(GetPlayerId(), GetCurrentTime()); + manager()->OnTimeChanged(GetPlayerId()); + } +} + +bool MediaPlayerBridgeGstreamer::SeekTo( + gint64 position, + float rate, + GstSeekFlags seekType) { + gint64 startTime = 0, endTime = 0; + if (rate > 0) { + startTime = position; + endTime = GST_CLOCK_TIME_NONE; + } else { + startTime = 0; + // If we are at beginning of media, start from the end to + // avoid immediate EOS. + if (position < 0) + endTime = static_cast(GetCurrentTime() * GST_SECOND); + else + endTime = position; + } + + return gst_element_seek(gst_playbin_, rate, GST_FORMAT_TIME, seekType, + GST_SEEK_TYPE_SET, startTime, GST_SEEK_TYPE_SET, endTime); +} + +void MediaPlayerBridgeGstreamer::Release() { + VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); + StopCurrentTimeUpdateTimer(); + StopBufferingUpdateTimer(); + if (gst_playbin_) { + GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(gst_playbin_)); + if (bus) { + g_signal_handlers_disconnect_by_func( + bus, reinterpret_cast(gst_pipeline_message_cb), this); +#if GST_VERSION_MAJOR == 1 + gst_bus_set_sync_handler(bus, NULL, NULL, NULL); +#else + gst_bus_set_sync_handler(bus, NULL, NULL); +#endif + gst_object_unref(bus); + } + + gst_element_set_state(gst_playbin_, GST_STATE_NULL); + gst_object_unref(gst_playbin_); + gst_playbin_ = NULL; + gst_appsink_ = NULL; + } +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + if (m_damage) { + ecore_x_damage_free(m_damage); + m_damage = 0; + } + if (m_damageHandler) { + ecore_event_handler_del(m_damageHandler); + m_damageHandler = NULL; + } + if (efl_pixmap_.get()) { + efl_pixmap_ = NULL; + } +#endif +} + +void MediaPlayerBridgeGstreamer::SetVolume(double volume) { + g_object_set(G_OBJECT(gst_playbin_), kPropertyVolume, volume, NULL); +} + +void MediaPlayerBridgeGstreamer::UpdateMediaType() { + int audio_stream_count = 0; + int video_stream_count = 0; + int text_stream_count = 0; + + g_object_get( + G_OBJECT(gst_playbin_), kPropertyAudioStream, &audio_stream_count, NULL); + g_object_get( + G_OBJECT(gst_playbin_), kPropertyVideoStream, &video_stream_count, NULL); + g_object_get( + G_OBJECT(gst_playbin_), kPropertyTextStream, &text_stream_count, NULL); + media_type_ = ((audio_stream_count ? MEDIA_AUDIO_MASK : 0) | + (video_stream_count ? MEDIA_VIDEO_MASK : 0)); + + // For Video-Sink Implementation we won't be getting Prepare-xid if we have + // only audio. + if (is_pixmap_used_ && video_stream_count == 0) + manager()->OnMediaDataChange( + GetPlayerId(), video_format_, gst_height_, gst_width_, media_type_); +} + +void MediaPlayerBridgeGstreamer::UpdateDuration() { + if (error_occured_) + return; + + gint64 duration = 0; + GstFormat format = GST_FORMAT_TIME; +#if GST_VERSION_MAJOR == 1 + gst_element_query_duration(gst_playbin_, format, &duration); +#else + gst_element_query_duration(gst_playbin_, &format, &duration); +#endif + duration_ = ConvertNanoSecondsToSeconds(duration); + manager()->OnDurationChange(GetPlayerId(), duration_); + // No need to sample 'local file'. Update buffered percentage. + if(is_file_url_) { + std::vector buffer_range; + media::MediaPlayerEfl::TimeRanges range; + range.start = 0; + range.end = duration_ * base::Time::kMicrosecondsPerSecond; + buffer_range.push_back(range); + manager()->OnBufferUpdate(GetPlayerId(), buffer_range); + } +} + +double MediaPlayerBridgeGstreamer::GetCurrentTime() { + if (error_occured_) + return 0.0; + + gint64 current_time = 0; + GstFormat format = GST_FORMAT_TIME; + + if (is_end_reached_) { + // Position queries on a null pipeline return 0. If we're at + // the end of the stream the pipeline is null but we want to + // report either the seek time or the duration because this is + // what the Media element spec expects us to do. + if (is_seeking_) + return seek_duration_; + + // Workaround for + // https://bugzilla.gnome.org/show_bug.cgi?id=639941 In GStreamer + // 0.10.35 basesink reports wrong duration in case of EOS and + // negative playback rate. There's no upstream accepted patch for + // this bug yet, hence this temporary workaround. + if (playback_rate_ < 0) + return 0.0f; + if (duration_) + return duration_; + + // FIXME: Should null be sent here? + } + +#if GST_VERSION_MAJOR == 1 + gst_element_query_position(gst_playbin_, format, ¤t_time); +#else + gst_element_query_position(gst_playbin_, &format, ¤t_time); +#endif + return ConvertNanoSecondsToSeconds(current_time); +} + +void MediaPlayerBridgeGstreamer::OnCurrentTimeUpdateTimerFired() { + manager()->OnTimeUpdate(GetPlayerId(), GetCurrentTime()); +} + +void MediaPlayerBridgeGstreamer::StartCurrentTimeUpdateTimer() { + if (!current_time_update_timer_.IsRunning()) { + current_time_update_timer_.Start( + FROM_HERE, + base::TimeDelta::FromMilliseconds(kDurationUpdateInterval), + this, &MediaPlayerBridgeGstreamer::OnCurrentTimeUpdateTimerFired); + } +} + +void MediaPlayerBridgeGstreamer::StopCurrentTimeUpdateTimer() { + if (current_time_update_timer_.IsRunning()) + current_time_update_timer_.Stop(); +} + +void MediaPlayerBridgeGstreamer::OnBufferingUpdateTimerFired() { + if (IsPlayerDestructing()) + return; + GetBufferedTimeRanges(); +} + +void MediaPlayerBridgeGstreamer::StartBufferingUpdateTimer() { + if (!buffering_update_timer_.IsRunning()) { + buffering_update_timer_.Start( + FROM_HERE, + base::TimeDelta::FromMilliseconds(kDurationUpdateInterval), + this, &MediaPlayerBridgeGstreamer::OnBufferingUpdateTimerFired); + } +} + +void MediaPlayerBridgeGstreamer::StopBufferingUpdateTimer() { + if (buffering_update_timer_.IsRunning()) + buffering_update_timer_.Stop(); +} + +#if GST_VERSION_MAJOR == 1 +GstSample* MediaPlayerBridgeGstreamer::PullSample() { + return gst_app_sink_pull_sample(GST_APP_SINK(gst_appsink_)); +} + +void MediaPlayerBridgeGstreamer::SampleReady(GstSample* sample) { + GstMapInfo map; + GstBuffer* buffer = gst_sample_get_buffer(sample); + + if (!gst_buffer_map(buffer, &map, GST_MAP_READ)) { + LOG (ERROR) << "Sample contains invalid or no info!"; + return; + } + + if (!gst_width_ || !gst_height_) + GetFrameDetails(); + + base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds( + GST_BUFFER_TIMESTAMP(buffer) / base::Time::kNanosecondsPerMicrosecond); + + if (video_format_ == GST_VIDEO_SN12) + shared_memory_size = (bufsize_sn12_); + else + shared_memory_size = (map.size); + + if (!shared_memory.CreateAndMapAnonymous(shared_memory_size)) { + LOG (ERROR) << "Shared Memory creation failed."; + gst_buffer_unmap(buffer, &map); + gst_sample_unref(sample); + return; + } + if (!shared_memory.ShareToProcess( + base::Process::Current().Handle(), &foreign_memory_handle)) { + LOG (ERROR) << "Shared Memory handle could not be obtained"; + shared_memory.Close(); + gst_buffer_unmap(buffer, &map); + gst_sample_unref(sample); + return; + } + memcpy(shared_memory.memory(), map.data, shared_memory_size); + manager()->OnNewFrameAvailable( + GetPlayerId(), foreign_memory_handle, shared_memory_size, timestamp); + + shared_memory.Close(); + gst_buffer_unmap(buffer, &map); + gst_sample_unref(sample); +} +#else +GstBuffer* MediaPlayerBridgeGstreamer::PullSample() { + return gst_app_sink_pull_buffer(GST_APP_SINK(gst_appsink_)); +} + +void MediaPlayerBridgeGstreamer::SampleReady( + const GstBuffer* buffer) { + if (!GST_BUFFER_DATA(buffer) || !GST_BUFFER_SIZE(buffer)) + return; + + if (!gst_width_ || !gst_height_) + GetFrameDetails(); + // FIXME: Cross check the end results. + + base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds( + GST_BUFFER_TIMESTAMP(buffer) / base::Time::kNanosecondsPerMicrosecond); + + uint8* buffer_data = GST_BUFFER_DATA(buffer); + gsize buffer_size = GST_BUFFER_SIZE(buffer); + if (video_format_ == GST_VIDEO_SN12) { + shared_memory_size = (bufsize_sn12_); + } else { + shared_memory_size = (buffer_size); + } + + if (!shared_memory.CreateAndMapAnonymous(shared_memory_size)) { + LOG (ERROR) << "Shared Memory creation failed."; + gst_buffer_unref(GST_BUFFER(buffer)); + return; + } + if (!shared_memory.ShareToProcess( + base::Process::Current().Handle(), &foreign_memory_handle)) { + LOG (ERROR) << "Shared Memory handle could not be obtained"; + shared_memory.Close(); + gst_buffer_unref(GST_BUFFER(buffer)); + return; + } + + memcpy(shared_memory.memory(), buffer_data, shared_memory_size); + manager()->OnNewFrameAvailable( + GetPlayerId(), foreign_memory_handle, shared_memory_size, timestamp); + + shared_memory.Close(); + gst_buffer_unref(GST_BUFFER(buffer)); +} +#endif + +// Updates networkState and ReadyState based on buffering percentage. +void MediaPlayerBridgeGstreamer::ProcessBufferingStats(GstMessage* message) { + if (IsPlayerDestructing()) + return; + + gst_message_parse_buffering(message, &buffered_); + main_loop_->PostTask(FROM_HERE, base::Bind( + &MediaPlayerBridgeGstreamer::OnUpdateStates, base::Unretained(this))); +} + +// To Update Buffered Ranges for Media Playback +void MediaPlayerBridgeGstreamer::GetBufferedTimeRanges() { + GstQuery *query = NULL; + gboolean result = false; + media::Ranges time_ranges; + std::vector buffer_range; + query = gst_query_new_buffering (GST_FORMAT_PERCENT); + result = gst_element_query(gst_playbin_, query); + if (result) { + gint n_ranges = 0, range = 0; + n_ranges = gst_query_get_n_buffering_ranges(query); + for (range = 0; range < n_ranges; range++) { + gint64 start = 0, stop = 0; + gst_query_parse_nth_buffering_range(query, range, &start, &stop); + media::MediaPlayerEfl::TimeRanges b_range; + +#if GST_VERSION_MAJOR == 1 + if ((start == 0 || is_end_reached_) && + stop == GST_FORMAT_PERCENT_MAX) + StopBufferingUpdateTimer(); + + b_range.start = start * duration_; + b_range.end = stop * duration_; +#else + // Stop the Timer on Buffer completion + if(start == 0 && stop == 100) + StopBufferingUpdateTimer(); + + // Parsed value is in percentage. Converted into time range + b_range.start = static_cast(start) * duration_ / 100 + * base::Time::kMicrosecondsPerSecond; + b_range.end = static_cast(stop) * duration_ / 100 + * base::Time::kMicrosecondsPerSecond; +#endif + + buffer_range.push_back(b_range); + } + manager()->OnBufferUpdate(GetPlayerId(), buffer_range); + } +} + +void MediaPlayerBridgeGstreamer::HandleMessage(GstMessage* message) { + if (IsPlayerDestructing()) + return; + + if (!strcmp(kPlaybinName, GST_MESSAGE_SRC_NAME(message))) + VLOG(1) << "MediaPlayerBridgeGstreamer::" << __FUNCTION__ + << " received from element " << GST_MESSAGE_SRC_NAME(message) + << " ID " << GetPlayerId(); + + const GstStructure* structure = gst_message_get_structure(message); + if (structure) { + const gchar* messageTypeName = gst_structure_get_name(structure); + + // Redirect messages are sent from elements, like qtdemux, to + // notify of the new location(s) of the media. + if (!g_strcmp0(messageTypeName, "redirect")) { + // FIXME: for changing media location + return; + } + } + + //FIXME: Add and handle all conditions + switch (GST_MESSAGE_TYPE(message)) { + case GST_MESSAGE_ERROR: + if (missing_plugins_) + break; + + StopBufferingUpdateTimer(); + GError* error; + gst_message_parse_error(message, &error, NULL); + MediaPlayerEfl::NetworkState network_state_error; + network_state_error = MediaPlayerEfl::NetworkStateEmpty; + if (error->code == GST_STREAM_ERROR_CODEC_NOT_FOUND + || error->code == GST_STREAM_ERROR_WRONG_TYPE + || error->code == GST_STREAM_ERROR_FAILED + || error->code == GST_CORE_ERROR_MISSING_PLUGIN + || error->code == GST_RESOURCE_ERROR_NOT_FOUND) { + network_state_error = MediaPlayerEfl::NetworkStateFormatError; + } else if (error->domain == GST_RESOURCE_ERROR) { + network_state_error = MediaPlayerEfl::NetworkStateNetworkError; + } else { + network_state_error = MediaPlayerEfl::NetworkStateDecodeError; + } + + LOG(ERROR) << "Error Message : " << error->message << " Recieved From : " + << GST_MESSAGE_SRC_NAME(message) + << ", and Blink Error Code = " << network_state_error; + g_error_free(error); + + HandleError(network_state_error); + break; + case GST_MESSAGE_EOS: + VLOG(1) << "Got GST_MESSAGE_EOS"; + main_loop_->PostTask(FROM_HERE, base::Bind( + &MediaPlayerBridgeGstreamer::OnPlaybackComplete, base::Unretained(this))); + break; + case GST_MESSAGE_ASYNC_DONE: + if (is_seeking_) { + UpdateSeekState(false); + main_loop_->PostTask(FROM_HERE, base::Bind( + &MediaPlayerBridgeGstreamer::OnTimeChanged, base::Unretained(this))); + } + + // Without |audio-sink| for audio tracks no preroll message is received. To + // update track details |PrerollComplete| is called. For Video tracks, + // preroll message is received long before control reaches here. + if (!is_prerolled_) + PrerollComplete(); + break; + case GST_MESSAGE_STATE_CHANGED: + if (strcmp(kPlaybinName, GST_MESSAGE_SRC_NAME(message))) + break; + + main_loop_->PostTask(FROM_HERE, base::Bind( + &MediaPlayerBridgeGstreamer::OnUpdateStates, base::Unretained(this))); + break; + case GST_MESSAGE_BUFFERING: + ProcessBufferingStats(message); + break; + case GST_MESSAGE_ELEMENT: + if (gst_is_missing_plugin_message(message)) { + gchar* detail = gst_missing_plugin_message_get_installer_detail(message); + gchar* detailArray[2] = {detail, 0}; + GstInstallPluginsReturn result = gst_install_plugins_async( + detailArray, 0, on_gst_installer_result_function, this); + missing_plugins_ = result == GST_INSTALL_PLUGINS_STARTED_OK; + g_free(detail); + } + + //gst_message_has_name (msg, "prepare-window-handle") +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + if (!IsXWindowHadleSet() && +#if GST_VERSION_MAJOR == 1 + gst_is_video_overlay_prepare_window_handle_message(message)) { +#else + gst_structure_has_name(message->structure, "prepare-xid")) { +#endif + LOG(INFO) << "Received message : Video overlay prepared"; + XWindowIdPrepared(message); + gst_message_unref(message); + return; + } +#endif + break; + default: + LOG(ERROR) << "Unhandled GStreamer message type: " + << GST_MESSAGE_TYPE_NAME(message); + break; + } +} + +void MediaPlayerBridgeGstreamer::HandlePluginInstallerResult( + GstInstallPluginsReturn result) { + missing_plugins_ = false; + if (result == GST_INSTALL_PLUGINS_SUCCESS) { + // FIXME: CAN CAUSE DEADLOCK? + gst_element_set_state(gst_playbin_, GST_STATE_READY); + gst_element_set_state(gst_playbin_, GST_STATE_PAUSED); + } else { + LOG(ERROR) << "GST Plugin Installation failed"; + HandleError(MediaPlayerEfl::NetworkStateDecodeError); + } +} + +void MediaPlayerBridgeGstreamer::UpdateStates() { + if (IsPlayerDestructing()) + return; + + if (error_occured_) + return; + + GstState state = GST_STATE_NULL; + GstState pending = GST_STATE_NULL; + GstStateChangeReturn ret = gst_element_get_state( + gst_playbin_, &state, &pending, 250 * GST_NSECOND); + + VLOG(1) << "MediaPlayerBridgeGstreamer::" + << __FUNCTION__ + << " GstStateChangeReturn: " + << gst_element_state_change_return_get_name(ret) + << " state: " + << gst_element_state_get_name(state) + << " pending: " + << gst_element_state_get_name(pending) + << " ID " << GetPlayerId(); + + // FIXME: Handle all state changes + switch (ret) { + case GST_STATE_CHANGE_SUCCESS: + if (!duration_) + UpdateDuration(); + + switch (state) { + case GST_STATE_NULL: + manager()->OnReadyStateChange( + GetPlayerId(), MediaPlayerEfl::ReadyStateHaveNothing); + manager()->OnNetworkStateChange( + GetPlayerId(), MediaPlayerEfl::NetworkStateEmpty); + break; + case GST_STATE_READY: + manager()->OnReadyStateChange( + GetPlayerId(), MediaPlayerEfl::ReadyStateHaveMetadata); + manager()->OnNetworkStateChange( + GetPlayerId(), MediaPlayerEfl::NetworkStateEmpty); + break; + case GST_STATE_PAUSED: + case GST_STATE_PLAYING: + if (!is_file_url_) + StartBufferingUpdateTimer(); + + VLOG(1) << "state " << gst_element_state_get_name(state) + << " buffered_ " << buffered_ + << " is_file_url_ " << is_file_url_ + << " is_paused_ " << is_paused_ + << " is_seeking_ " << is_seeking_; + + if (buffered_ == 100 || is_file_url_) { + if (state == GST_STATE_PAUSED && !is_paused_) { + if (gst_element_set_state(gst_playbin_, GST_STATE_PLAYING) + == GST_STATE_CHANGE_FAILURE) + LOG(ERROR) << "GStreamer state change failed"; + } + + // FIXME: On rapid playback on PIANO Widget, there are instences + // when 'ASYNC-DONE' message is not received on replay. + if (is_seeking_ && state == GST_STATE_PLAYING) { + LOG(ERROR) << "PLAYING state changed on seek"; + UpdateSeekState(false); + main_loop_->PostTask(FROM_HERE, + base::Bind(&MediaPlayerBridgeGstreamer::OnTimeChanged, + base::Unretained(this))); + } + manager()->OnReadyStateChange( + GetPlayerId(), MediaPlayerEfl::ReadyStateHaveEnoughData); + manager()->OnNetworkStateChange( + GetPlayerId(), MediaPlayerEfl::NetworkStateLoaded); + } else { + if (state == GST_STATE_PLAYING) { + if (gst_element_set_state(gst_playbin_, GST_STATE_PAUSED) + == GST_STATE_CHANGE_FAILURE) + LOG(ERROR) << "GStreamer state change failed"; + manager()->OnReadyStateChange( + GetPlayerId(), MediaPlayerEfl::ReadyStateHaveCurrentData); + manager()->OnNetworkStateChange( + GetPlayerId(), MediaPlayerEfl::NetworkStateLoading); + } + } + break; + default: + LOG(ERROR) << "GStreamer unhandled state " + << gst_element_state_get_name(state); + break; + } + break; + case GST_STATE_CHANGE_ASYNC: + // FIXME: For live stream. + break; + case GST_STATE_CHANGE_FAILURE: + LOG(ERROR) << "Failure: State: " + << gst_element_state_get_name(state) + << " pending: " + << gst_element_state_get_name(pending); + HandleError(MediaPlayerEfl::NetworkStateDecodeError); + break; + case GST_STATE_CHANGE_NO_PREROLL: + if (state == GST_STATE_READY) { + manager()->OnReadyStateChange( + GetPlayerId(), MediaPlayerEfl::ReadyStateHaveNothing); + } else if (state == GST_STATE_PAUSED) { + manager()->OnReadyStateChange( + GetPlayerId(), MediaPlayerEfl::ReadyStateHaveEnoughData); + is_paused_ = true; + is_live_stream_ = true; + } else if (state == GST_STATE_PLAYING) { + is_paused_ = false; + } + manager()->OnNetworkStateChange( + GetPlayerId(), MediaPlayerEfl::NetworkStateLoading); + break; + default: + LOG(ERROR) << "Unhandled return type: " << ret; + break; + } +} + +void MediaPlayerBridgeGstreamer::FrameReady( + const scoped_refptr& frame) { +} + +void MediaPlayerBridgeGstreamer::GetFrameDetails() { +#if GST_VERSION_MAJOR == 1 + GstSample* sample = gst_app_sink_pull_preroll(GST_APP_SINK(gst_appsink_)); + if (!sample) + return; + + GstCaps* caps = gst_sample_get_caps(sample); + if (!caps) + return; + + GstVideoInfo vi; + gst_video_info_from_caps(&vi, caps); + + gst_width_ = GST_VIDEO_INFO_WIDTH(&vi); + gst_height_ = GST_VIDEO_INFO_HEIGHT(&vi); + switch(GST_VIDEO_INFO_FORMAT(&vi)) { + case GST_VIDEO_FORMAT_I420:{ + video_format_ = GST_MAKE_FOURCC('I','4','2','0'); + break; + } + case GST_VIDEO_FORMAT_NV12:{ + video_format_ = GST_MAKE_FOURCC('N','V','1','2'); + break; + } + default: + LOG(ERROR) << "Unknown format : " << GST_VIDEO_INFO_FORMAT(&vi); + break; + } +#else + GstBuffer* sample = gst_app_sink_pull_preroll(GST_APP_SINK(gst_appsink_)); + if (!sample) + return; + + GstCaps* caps = gst_buffer_get_caps(GST_BUFFER(sample)); + if (!caps) + return; + + const GstStructure* str = gst_caps_get_structure(caps, 0); + gst_caps_unref(caps); + if (!str) + return; + + if (!gst_structure_get_int(str, "width", &gst_width_) || + !gst_structure_get_int(str, "height", &gst_height_) || + !gst_structure_get_fourcc(str, "format", &video_format_)) + LOG(ERROR) << "Pre-roll buffer info could not be obtained"; +#endif + + // Need to update frame details before sending sample. + manager()->OnMediaDataChange( + GetPlayerId(), static_cast(video_format_), + gst_height_, gst_width_, media_type_); + + if (video_format_ == GST_VIDEO_SN12) { + uint tile_w_align = ((gst_width_ - 1) / SN12_TILE_WIDTH + 2) & ~1; + bufsize_sn12_ = SN12_TILE_SIZE * tile_w_align * ((gst_height_ - 1) / + SN12_TILE_HEIGHT + 1) + (((gst_height_ + 1) & ~1) / 2) * tile_w_align * + SN12_TILE_WIDTH; + } + + SampleReady(sample); +} + +// FIXME: Works well for video playback. Do the same for /consider audio +// prerolling. +void MediaPlayerBridgeGstreamer::PrerollComplete() { + if(!is_pixmap_used_) { + UpdateMediaType(); + if (media_type_ & MEDIA_VIDEO_MASK) + GetFrameDetails(); + else + manager()->OnMediaDataChange( + GetPlayerId(), static_cast(video_format_), + gst_height_, gst_width_, media_type_); + + VLOG(1) << "MediaPlayerBridgeGstreamer::PrerollComplete." + << " video_format " << video_format_ + << " width " << gst_width_ + << " height " << gst_height_ + << " media_type " << media_type_; + } else { + UpdateMediaType(); + } + is_prerolled_ = true; +} + +void MediaPlayerBridgeGstreamer::OnPlaybackComplete() { + VLOG(1) << "OnPlaybackComplete" << " ID " << GetPlayerId(); + is_end_reached_ = true; + +#if defined(OS_TIZEN_MOBILE) && (defined(TIZEN_V_2_3) || defined(TIZEN_V_2_4)) + if (device_power_release_lock(POWER_LOCK_DISPLAY) != DEVICE_ERROR_NONE) + LOG(ERROR) << "|device_power_release_lock| request failed"; +#endif + + StopCurrentTimeUpdateTimer(); + manager()->OnTimeUpdate(GetPlayerId(), GetCurrentTime()); + manager()->OnTimeChanged(GetPlayerId()); +} + +void MediaPlayerBridgeGstreamer::UpdateSeekState(bool state) { + is_seeking_ = state; +} + +void MediaPlayerBridgeGstreamer::OnTimeChanged() { + VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); + DCHECK(main_loop_->BelongsToCurrentThread()); + manager()->OnTimeChanged(GetPlayerId()); +} + +void MediaPlayerBridgeGstreamer::OnUpdateStates() { + VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); + DCHECK(main_loop_->BelongsToCurrentThread()); + UpdateStates(); +} + +GstElement* MediaPlayerBridgeGstreamer::GetVideoSink() { +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + is_pixmap_used_ = true; + return gst_element_factory_make("xvimagesink", kVideoSink); +#else + is_pixmap_used_ = false; + return gst_element_factory_make("appsink", kVideoSink); +#endif +} + +void MediaPlayerBridgeGstreamer::PrepareForVideoFrame() { + VLOG(1) << "MediaElement using shared memory to pass the frames"; + int flags = 0; + g_object_get(gst_playbin_, "flags", &flags, NULL); + flags = GST_PLAY_FLAG_NATIVE_VIDEO | GST_PLAY_FLAG_NATIVE_AUDIO + | GST_PLAY_FLAG_DOWNLOAD; +#ifdef OS_TIZEN_TV + flags |= GST_PLAY_FLAG_NATIVE_VIDEO | GST_PLAY_FLAG_NATIVE_AUDIO; + flags &= ~GST_PLAY_FLAG_VIDEO & ~GST_PLAY_FLAG_AUDIO & + ~GST_PLAY_FLAG_DEINTERLACE & ~GST_PLAY_FLAG_SOFT_COLORBALANCE; +#if defined(TIZEN_V_3_0) + flags |= GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_NATIVE_VIDEO; + flags &= ~GST_PLAY_FLAG_NATIVE_AUDIO; +#endif +#endif + g_object_set(gst_playbin_, "flags", flags, NULL); +#if GST_VERSION_MAJOR == 1 + GstAppSinkCallbacks callbacks = {on_gst_appsink_eos, on_gst_appsink_preroll, + on_gst_appsink_sample}; +#else + GstAppSinkCallbacks callbacks = {on_gst_appsink_eos, + on_gst_appsink_preroll, + on_gst_appsink_sample, + NULL, + {NULL, NULL, NULL}}; +#endif + gst_app_sink_set_callbacks(GST_APP_SINK(gst_appsink_), &callbacks, + this, NULL); + + g_object_set(G_OBJECT(gst_playbin_), kPropertyBufferSize, + kPreloadBufferSize, NULL); + g_object_set(G_OBJECT(gst_appsink_), kPropertyMaxBuffers, + (guint)kMaxBuffer, NULL); +} + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +void MediaPlayerBridgeGstreamer::PrepareForVideoSink() { + VLOG(1) << "MediaElement Backed by Video-Sink (xvimagesink)"; + int flags = 0; + g_object_get(gst_playbin_, "flags", &flags, NULL); + flags |= GST_PLAY_FLAG_NATIVE_VIDEO; + flags &= ~GST_PLAY_FLAG_TEXT; + g_object_set(gst_playbin_, "flags", flags, NULL); +} + +void MediaPlayerBridgeGstreamer::XWindowIdPrepared(GstMessage* message) { + // It is called just once after video src is set. +#if GST_VERSION_MAJOR == 1 + const GstStructure* structure = gst_message_get_structure(message); + gst_structure_get_int(structure, "video-width", &gst_width_); + gst_structure_get_int(structure, "video-height", &gst_height_); +#else + gst_structure_get_int(message->structure, "video-width", &gst_width_); + gst_structure_get_int(message->structure, "video-height", &gst_height_); +#endif + SetPixmap(); +} + +int MediaPlayerBridgeGstreamer::GetSurfaceID() const { + return pixmap_id_; +} + +void MediaPlayerBridgeGstreamer::SetPixmap() { + efl_pixmap_ = gfx::EflPixmap::Create(gfx::EflPixmap::SURFACE, gfx::Size( + gst_width_, gst_height_)); + if (!efl_pixmap_.get()) { + LOG(ERROR) << "gfx::EflPixmap::Create() failed to create Pixmap"; + return ; + } + pixmap_id_ = efl_pixmap_->GetId(); + g_object_set (gst_appsink_, "pixmap-id-callback", get_pixmap_id_cb, NULL); + g_object_set (gst_appsink_, "pixmap-id-callback-userdata", this, NULL); + + //Register to get notification from ecore for damage updates. + m_damage = ecore_x_damage_new( + pixmap_id_, ECORE_X_DAMAGE_REPORT_RAW_RECTANGLES); + m_damageHandler = ecore_event_handler_add( + ECORE_X_EVENT_DAMAGE_NOTIFY, notify_damage_updated_cb, this); + g_object_set(gst_appsink_, "rotate", DEGREE_0, NULL); + + // Passing NUL value for video_format. Its not required but + // |webmediaplayertizen| expects a value. + UpdateMediaType(); + manager()->OnMediaDataChange( + GetPlayerId(), video_format_, gst_height_, gst_width_, media_type_); +} + +void MediaPlayerBridgeGstreamer::PlatformSurfaceUpdated() { + gint64 current_time = 0; + GstFormat format = GST_FORMAT_TIME; +#if GST_VERSION_MAJOR == 1 + gst_element_query_position(gst_playbin_, format, ¤t_time); +#else + gst_element_query_position(gst_playbin_, &format, ¤t_time); +#endif + base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds( + current_time / base::Time::kNanosecondsPerMicrosecond); + manager()->OnPlatformSurfaceUpdated(GetPlayerId(), pixmap_id_, timestamp); +} +#endif + +void MediaPlayerBridgeGstreamer::HandleError( + media::MediaPlayerEfl::NetworkState state) { + LOG(ERROR) << "Error in MediaPlayerBridgeGstreamer::HandleError"; +#if defined(OS_TIZEN_MOBILE) && (defined(TIZEN_V_2_3) || defined(TIZEN_V_2_4)) + if (device_power_release_lock(POWER_LOCK_DISPLAY) != DEVICE_ERROR_NONE) + LOG(ERROR) << "|device_power_release_lock| request failed"; +#endif + + error_occured_ = true; + manager()->OnNetworkStateChange(GetPlayerId(), state); +} + +} // namespace media diff --git a/tizen_src/chromium_impl/media/base/efl/media_player_bridge_gstreamer.h b/tizen_src/chromium_impl/media/base/efl/media_player_bridge_gstreamer.h new file mode 100644 index 000000000000..64826b10e37a --- /dev/null +++ b/tizen_src/chromium_impl/media/base/efl/media_player_bridge_gstreamer.h @@ -0,0 +1,156 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_TIZEN_MEDIA_PLAYER_BRIDGE_GSTREMEAR_H_ +#define MEDIA_TIZEN_MEDIA_PLAYER_BRIDGE_GSTREMEAR_H_ + +#include +#include +#include + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +#include +#include +#endif + +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/timer/timer.h" +#include "content/public/browser/browser_message_filter.h" +#include "media/base/ranges.h" +#include "media/base/efl/media_player_efl.h" +#include "media/base/video_frame.h" + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +#include "ui/gl/efl_pixmap.h" +#endif + +namespace media { + +class MEDIA_EXPORT MediaPlayerBridgeGstreamer + : public MediaPlayerEfl { + public: + MediaPlayerBridgeGstreamer( + int player_id, + const GURL& url, + double volume, + MediaPlayerManager* manager); + virtual ~MediaPlayerBridgeGstreamer(); + + // MediaPlayerEfl implementation. + virtual void Play() override; + virtual void Pause(bool is_media_related_action) override; + virtual void SetRate(double rate) override; + virtual void Seek(const double time) override; + virtual void SetVolume(double volume) override; + virtual double GetCurrentTime() override; + virtual void Destroy() override; + + // Error handling API + void HandleError(media::MediaPlayerEfl::NetworkState state); + + void HandleMessage(GstMessage* message); + void HandlePluginInstallerResult(GstInstallPluginsReturn result); +#if GST_VERSION_MAJOR == 1 + GstSample* PullSample(); + void SampleReady(GstSample* buffer); +#else + GstBuffer* PullSample(); + void SampleReady(const GstBuffer* buffer); +#endif + void PrerollComplete(); + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + void PlatformSurfaceUpdated(); + int GetSurfaceID() const; +#endif + + protected: + void Release() override; + + private: + // |duration_update_timer_| related + void OnCurrentTimeUpdateTimerFired(); + void StartCurrentTimeUpdateTimer(); + void StopCurrentTimeUpdateTimer(); + + // |Buffering_update_timer_| related + void OnBufferingUpdateTimerFired(); + void StartBufferingUpdateTimer(); + void StopBufferingUpdateTimer(); + + void UpdateStates(); + void OnUpdateStates(); + void UpdateDuration(); + void UpdateMediaType(); + void UpdateSeekState(bool state); + + void OnPlaybackComplete(); + void OnTimeChanged(); + + void FrameReady(const scoped_refptr& frame); + void GetFrameDetails(); + void ProcessBufferingStats(GstMessage* message); + void GetBufferedTimeRanges(); + bool SeekTo(gint64 position, float rate, GstSeekFlags seekType); + + GstElement* GetVideoSink(); + void PrepareForVideoFrame(); + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + void PrepareForVideoSink(); + void XWindowIdPrepared(GstMessage*); + bool IsXWindowHadleSet(){return pixmap_id_ ? true : false ;} + void SetPixmap(); +#endif + + private: + const scoped_refptr main_loop_; + GstElement* gst_playbin_; + GstElement* gst_appsink_; + GURL url_; + double volume_; + gint gst_width_; + gint gst_height_; + + bool is_prerolled_; + bool is_paused_; + double duration_; + double playback_rate_; + int buffered_; + guint32 video_format_; + + int media_type_; + bool is_live_stream_; + bool is_file_url_; + bool is_end_reached_ ; + bool is_seeking_ ; + bool is_seek_pending_ ; + double seek_duration_; + + bool error_occured_; + bool missing_plugins_; + bool is_pixmap_used_; + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + int pixmap_id_; + scoped_refptr efl_pixmap_; + Ecore_X_Damage m_damage; + Ecore_Event_Handler* m_damageHandler; +#endif + uint bufsize_sn12_; + + base::SharedMemory shared_memory; + uint32 shared_memory_size; + base::SharedMemoryHandle foreign_memory_handle; + + base::RepeatingTimer current_time_update_timer_; + base::RepeatingTimer buffering_update_timer_; + + DISALLOW_COPY_AND_ASSIGN(MediaPlayerBridgeGstreamer); +}; + +} // namespace media + +#endif // MEDIA_TIZEN_MEDIA_PLAYER_BRIDGE_GSTREMEAR_H_ diff --git a/tizen_src/chromium_impl/media/base/efl/media_player_efl.h b/tizen_src/chromium_impl/media/base/efl/media_player_efl.h new file mode 100644 index 000000000000..657b7be50a99 --- /dev/null +++ b/tizen_src/chromium_impl/media/base/efl/media_player_efl.h @@ -0,0 +1,113 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_TIZEN_MEDIA_PLAYER_TIZEN_H_ +#define MEDIA_TIZEN_MEDIA_PLAYER_TIZEN_H_ + +#include + +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/time/time.h" +#include "content/common/media/efl/media_player_messages_enums_efl.h" +#include "media/base/media_export.h" +#include "url/gurl.h" + +namespace media { + +class MediaDrmBridge; +class MediaPlayerManager; + +// Error types for MediaErrorCB. +enum MediaErrorType { + MEDIA_ERROR_FORMAT, + MEDIA_ERROR_DECODE, + MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK, + MEDIA_ERROR_INVALID_CODE, +}; + +// media type masks +const int MEDIA_AUDIO_MASK = 0x02; +const int MEDIA_VIDEO_MASK = 0x01; + +class MEDIA_EXPORT MediaPlayerEfl{ + public: + // FIXME: Remove these enum and use webkit's + enum ReadyState { + ReadyStateHaveNothing, + ReadyStateHaveMetadata, + ReadyStateHaveCurrentData, + ReadyStateHaveFutureData, + ReadyStateHaveEnoughData, + }; + + enum NetworkState { + NetworkStateEmpty, + NetworkStateIdle, + NetworkStateLoading, + NetworkStateLoaded, + NetworkStateFormatError, + NetworkStateNetworkError, + NetworkStateDecodeError, + }; + + typedef struct range { + int64 start; + int64 end; + } TimeRanges; + + MediaPlayerEfl() { } + virtual ~MediaPlayerEfl() { } + + // Start playing the media. + virtual void Play() = 0; + + // To Pause from HTMLMediaElement, pass |false| as argument. + // Pass |true| as argument when buffer is low in case of MediaSource. + virtual void Pause(bool is_media_related_action) = 0; + + virtual void SetRate(double rate) = 0; + + // Seek to a particular position, based on renderer signaling actual seek + // with MediaPlayerHostMsg_Seek. If eventual success, OnSeekComplete() will be + // called. + virtual void Seek(const double time) = 0; + + // Set the player volume. + virtual void SetVolume(double volume) = 0; + + // Get the media information from the player. + virtual double GetCurrentTime() = 0; + + int GetPlayerId() { return player_id_; } + + bool IsPlayerDestructing() { return destructing_; } + + // Destroy this object when all messages for it are delivered + virtual void Destroy() = 0; + + protected: + // Release the player resources. + virtual void Release() = 0; + + MediaPlayerEfl(int player_id, MediaPlayerManager* manager) + : destructing_(false), player_id_(player_id), manager_(manager) { } + + MediaPlayerManager* manager() { return manager_; } + + bool destructing_; + + private: + // Player ID assigned to this player. + int player_id_; + + // Resource manager for all the media players. + MediaPlayerManager* manager_; + + DISALLOW_COPY_AND_ASSIGN(MediaPlayerEfl); +}; + +} // namespace media + +#endif // MEDIA_TIZEN_MEDIA_PLAYER_TIZEN_H_ diff --git a/tizen_src/chromium_impl/media/base/efl/media_player_manager_efl.h b/tizen_src/chromium_impl/media/base/efl/media_player_manager_efl.h new file mode 100644 index 000000000000..7102fee27b18 --- /dev/null +++ b/tizen_src/chromium_impl/media/base/efl/media_player_manager_efl.h @@ -0,0 +1,57 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_BASE_TIZEN_MEDIA_PLAYER_TIZEN_MANAGER_H_ +#define MEDIA_BASE_TIZEN_MEDIA_PLAYER_TIZEN_MANAGER_H_ + +#include + +#include "base/memory/shared_memory.h" +#include "media/base/efl/media_player_efl.h" + +namespace media { + +class MediaPlayerEfl; + +class MEDIA_EXPORT MediaPlayerManager { + public: + virtual ~MediaPlayerManager() { } + virtual MediaPlayerEfl* GetPlayer(int player_id) = 0; + + virtual void OnTimeChanged(int player_id) = 0; + virtual void OnTimeUpdate(int player_id, double current_time) = 0; + virtual void OnRequestSeek(int player_id, double seek_time) = 0; + virtual void OnPauseStateChange(int player_id, bool state) = 0; + virtual void OnSeekStateChange(int player_id, bool state) = 0; + virtual void OnBufferUpdate( + int player_id, + std::vector buffer_range) = 0; + virtual void OnDurationChange(int player_id, double duration) = 0; + virtual void OnReadyStateChange(int player_id, + MediaPlayerEfl::ReadyState state) = 0; + virtual void OnNetworkStateChange( + int player_id, + MediaPlayerEfl::NetworkState state) = 0; + virtual void OnMediaDataChange( + int player_id, + int format, + int height, + int width, + int media) = 0; + virtual void OnNewFrameAvailable( + int player_id, + base::SharedMemoryHandle handle, + uint32 length, + base::TimeDelta timestamp) = 0; +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + virtual void OnPlatformSurfaceUpdated( + int player_id, + int pixmap_id, + base::TimeDelta timestamp) = 0; +#endif +}; + +} // namespace media + +#endif // MEDIA_BASE_TIZEN_MEDIA_PLAYER_TIZEN_MANAGER_H_ diff --git a/tizen_src/chromium_impl/media/base/efl/media_source_player_gstreamer.cc b/tizen_src/chromium_impl/media/base/efl/media_source_player_gstreamer.cc new file mode 100644 index 000000000000..6bbfe30a0ac9 --- /dev/null +++ b/tizen_src/chromium_impl/media/base/efl/media_source_player_gstreamer.cc @@ -0,0 +1,1889 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/base/efl/media_source_player_gstreamer.h" + +#include +#include +#include + +#include "base/process/process.h" +#include "media/base/efl/media_player_manager_efl.h" + +#if defined(OS_TIZEN_MOBILE) && (defined(TIZEN_V_2_3) || defined(TIZEN_V_2_4)) +#include +#endif + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +#if GST_VERSION_MAJOR == 1 +#include +#else +#include +#endif +#endif + +namespace { + +const uint32 GST_VIDEO_SN12 = GST_MAKE_FOURCC('S','N','1','2'); + +const uint SN12_TILE_WIDTH = 64; +const uint SN12_TILE_HEIGHT = 32; +const uint SN12_TILE_SIZE = SN12_TILE_WIDTH * SN12_TILE_HEIGHT; + +// Pipeline element name +const char* kPipelineName = "gst_pipeline"; + +// Update duration every 100ms. +const int kDurationUpdateInterval = 100; + +// For smooth playback, seeking will be done to I-Frame + kSixteenMilliSeconds +// Reason to choose kSixteenMilliSeconds is duration of each video frame at +// 60 fps video will be ~16 milliseconds. +const int64 kSixteenMilliSeconds = 16000000; + +const char *h264elements[] = { + "h264parse" +#if defined(OS_TIZEN_MOBILE) + , "avdec_h264" +#elif defined(OS_TIZEN_TV) +#if defined(TIZEN_V_3_0) + , "avdec_h264" +#else + , "omx_h264dec" +#endif +#else + , "ffdec_h264" +#endif +}; + +const char *aacelements[] = { + "aacparse" +#if defined(OS_TIZEN_MOBILE) + , "avdec_aac", "autoaudiosink" +#elif defined(OS_TIZEN_TV) +#if defined(TIZEN_V_3_0) + , "avdec_aac", "alsasink" +#else + , "omx_aacdec", "alsasink" +#endif +#else + , "faad", "autoaudiosink" +#endif +}; + +// FIXME: This is derived from command-line pipeline on desktop and mobile. +// Need to find the pipeline on TV. +// Also the connection might be different when converting it to code. +const char *mp3elements[] = { + "mpegaudioparse" +#if defined(OS_TIZEN_MOBILE) + , "avdec_mp3" +#else +#if defined(TIZEN_V_3_0) + , "avdec_mp3" +#else + , "ffdec_mp3" +#endif +#endif + ,"autoaudiosink" +}; + +const AudioCodecGstElementsMapping AudioMapping[] = { + {media::kCodecAAC, aacelements}, + {media::kCodecMP3, mp3elements}, + {media::kUnknownAudioCodec, NULL} +}; + +const VideoCodecGstElementsMapping VideoMapping[] = { + {media::kCodecH264, h264elements}, + {media::kUnknownVideoCodec, NULL} +}; + +GstClockTime ConvertToGstClockTime(double time) { + if (time < 0) { + LOG(ERROR) << "Invalid time:" << time << " Reset to 0"; + time = 0; + } + + // Extract the integer part of the time (seconds) and the fractional part + // (microseconds). Attempt to round the microseconds so no floating point + // precision is lost and we can perform an accurate seek. + double seconds; + double microSeconds = std::modf(time, &seconds) * 1000000; + GTimeVal timeValue; + timeValue.tv_sec = static_cast(seconds); + timeValue.tv_usec = static_cast(lround(microSeconds / 10) * 10); + return GST_TIMEVAL_TO_TIME(timeValue); +} + +double ConvertNanoSecondsToSeconds(int64 time) { + double seconds = static_cast(time) / + (base::Time::kNanosecondsPerSecond); + return seconds; +} + +} // namespace + +namespace media { + +static GstBusSyncReply gst_pipeline_message_cb( + GstBus* bus, + GstMessage* message, + gpointer user_data) { + MediaSourcePlayerGstreamer* player = + static_cast(user_data); + if (!player || player->IsPlayerDestructing()) + return GST_BUS_PASS; + + player->HandleMessage(message); + gst_message_unref(message); + return GST_BUS_DROP; +} + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +static Eina_Bool notify_damage_updated_cb( + void* user_data, + int type, + void* event) { + MediaSourcePlayerGstreamer* player = + static_cast(user_data); + if (!player || player->IsPlayerDestructing()) + return ECORE_CALLBACK_PASS_ON; + player->PlatformSurfaceUpdated(); + return ECORE_CALLBACK_PASS_ON; +} +#endif + +#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +static int get_pixmap_id_cb(void* user_data) { + MediaSourcePlayerGstreamer* player = + static_cast(user_data); + return player->GetSurfaceID(); +} +#endif + +static ASM_cb_result_t media_player_audio_session_event_source_pause( + ASM_event_sources_t event_source, + void* user_data) { + MediaPlayerEfl* player = + static_cast(user_data); + if (!player) { + return ASM_CB_RES_IGNORE; + } + + switch (event_source) { + case ASM_EVENT_SOURCE_CALL_START: + case ASM_EVENT_SOURCE_ALARM_START: + case ASM_EVENT_SOURCE_MEDIA: + case ASM_EVENT_SOURCE_EMERGENCY_START: + case ASM_EVENT_SOURCE_OTHER_PLAYER_APP: + case ASM_EVENT_SOURCE_RESOURCE_CONFLICT: + case ASM_EVENT_SOURCE_EARJACK_UNPLUG: + player->Pause(true); + return ASM_CB_RES_PAUSE; + default: + return ASM_CB_RES_NONE; + } +} + +static ASM_cb_result_t media_player_audio_session_event_source_play( + ASM_event_sources_t event_source, + void* user_data) { + MediaPlayerEfl* player = + static_cast(user_data); + if (!player) { + return ASM_CB_RES_IGNORE; + } + + switch (event_source) { + case ASM_EVENT_SOURCE_ALARM_END: + player->Play(); + return ASM_CB_RES_PLAYING; + default: + return ASM_CB_RES_NONE; + } +} + +static ASM_cb_result_t media_player_private_audio_session_notify_cb( + int, + ASM_event_sources_t event_source, + ASM_sound_commands_t command, + unsigned int, + void* user_data) { + if (command == ASM_COMMAND_STOP || command == ASM_COMMAND_PAUSE) + return media_player_audio_session_event_source_pause( + event_source, user_data); + if (command == ASM_COMMAND_PLAY || command == ASM_COMMAND_RESUME) + return media_player_audio_session_event_source_play( + event_source, user_data); + return ASM_CB_RES_NONE; +} +#endif + +static void on_gst_start_video_feed_cb( + GstAppSrc* pipeline, + guint size, + void *user_data) { + MediaSourcePlayerGstreamer* player = + static_cast(user_data); + if (!player || player->IsPlayerDestructing()) + return; + player->OnReadDemuxedData(media::DemuxerStream::VIDEO); + return ; +} + +static void on_gst_stop_video_feed_cb(GstAppSrc * pipeline,void *user_data) { + MediaSourcePlayerGstreamer* player = + static_cast(user_data); + if (!player || player->IsPlayerDestructing()) + return; + player->OnStopDemuxedData(media::DemuxerStream::VIDEO); +} + +static gboolean on_gst_seek_video_feed_cb( + GstAppSrc* pipeline, + guint64 offset, + void *user_data) { + + MediaSourcePlayerGstreamer* player = + static_cast(user_data); + if (!player || player->IsPlayerDestructing()) + return FALSE; + player->UpdateVideoSeekOffset(offset); + return TRUE; +} + +static GstFlowReturn on_gst_appsink_preroll( + GstAppSink* sink, + gpointer user_data) { + MediaSourcePlayerGstreamer* player = + static_cast(user_data); + if (!player || player->IsPlayerDestructing()) + return GST_FLOW_ERROR; + player->GetFrameDetails(); + return GST_FLOW_OK; +} + +static GstFlowReturn on_gst_appsink_sample( + GstAppSink* sink, + gpointer user_data) { + MediaSourcePlayerGstreamer* player = + static_cast(user_data); + if (!player || player->IsPlayerDestructing()) + return GST_FLOW_ERROR; + player->OnNewFrameAvailable(player->PullSample()); + return GST_FLOW_OK; +} + +gboolean on_gst_seek_audio_feed_cb( + GstAppSrc *pipeline, + guint64 offset, + void* user_data) { + MediaSourcePlayerGstreamer* player = + static_cast(user_data); + if (!player || player->IsPlayerDestructing()) + return FALSE; + player->UpdateAudioSeekOffset(offset); + return TRUE; +} + +static void on_gst_start_audio_feed_cb ( + GstAppSrc * pipeline, + guint size, + void* user_data) { + MediaSourcePlayerGstreamer* player = + static_cast(user_data); + if (!player || player->IsPlayerDestructing()) + return; + player->OnReadDemuxedData(media::DemuxerStream::AUDIO); +} + +static void on_gst_stop_audio_feed_cb(GstAppSrc* pipeline, void* user_data) { + MediaSourcePlayerGstreamer* player = + static_cast(user_data); + if (!player || player->IsPlayerDestructing()) + return; + player->OnStopDemuxedData(media::DemuxerStream::AUDIO); +} + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +static void on_video_sink_caps_changed_cb( + GObject* gobject, + GParamSpec* gparamspec, + void* user_data) { + MediaSourcePlayerGstreamer* player = + static_cast(user_data); + if (!player || player->IsPlayerDestructing()) + return; + player->OnVideoConfigsChanged(); +} +#endif + +// Generating Unique string from given width and height. +std::string ConvertWidthAndHeightToString(int width, int height) { + std::ostringstream width_stream, height_stream; + width_stream << width; + height_stream << height; + return width_stream.str() + "X" + height_stream.str(); +} + +MediaSourcePlayerGstreamer::MediaSourcePlayerGstreamer( + int player_id, + scoped_ptr demuxer, + MediaPlayerManager* manager) + : MediaPlayerEfl(player_id, manager), + demuxer_(demuxer.Pass()), + main_loop_(base::MessageLoopProxy::current()), +#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) + audio_session_manager_(AudioSessionManager::CreateAudioSessionManager()), +#endif + playing_(false), + weak_this_(this), +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + pixmap_id_(0), + efl_pixmap_(NULL), + m_damage(0), + m_damageHandler(0), +#endif + is_xwindow_handle_set_(false), + is_backed_by_pixmap(false), + pipeline_(NULL), + video_appsrc_(NULL), + video_parse_(NULL), + video_decoder_(NULL), + video_sink_(NULL), + audio_appsrc_(NULL), + audio_decoder_(NULL), + audio_sink_(NULL), + video_queue_(NULL), + audio_queue_(NULL), + audio_parse_(NULL), + audio_convert_(NULL), + audio_resampler_(NULL), + audio_volume_(NULL), + video_sink_pad_(NULL), + should_feed_audio_(true), + should_feed_video_(false), + gst_width_(0), + gst_height_(0), + video_format_(0), + media_type(0), + play_rate_(1.0f), + duration_(0), + is_paused_due_underflow_(false), + shared_memory_size(0), + buffered_(0), + is_paused_(false), + is_seeking_(false), + is_demuxer_seeking_(false), + audio_buffered_(0), + video_buffered_(0), + is_gst_pipeline_constructed_(false), + is_download_finished_(false), + is_end_reached_(false), + error_occured_(false), + raw_video_frame_size_(0), + video_seek_offset_(0), + audio_seek_offset_(0), + is_seeking_iframe_(false) { + demuxer_->Initialize(this); + audio_buffer_queue_.clear(); + video_buffer_queue_.clear(); +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + efl_pixmaps_map_.clear(); +#endif +#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) + if (!audio_session_manager_->RegisterAudioSessionManager( + MM_SESSION_TYPE_SHARE, + media_player_private_audio_session_notify_cb, this)) + return; +#endif +} + +MediaSourcePlayerGstreamer::~MediaSourcePlayerGstreamer() { + VLOG(1) << "MediaSourcePlayerGstreamer::" << __FUNCTION__ + << "Player ID:" << GetPlayerId(); +} + +void MediaSourcePlayerGstreamer::Destroy() { + if (IsPlayerDestructing()) + return; + + VLOG(1) << "MediaSourcePlayerGstreamer::" << __FUNCTION__ + << "Player ID:" << GetPlayerId(); + destructing_ = true; + Release(); + main_loop_->DeleteSoon(FROM_HERE, this); +} + +void MediaSourcePlayerGstreamer::Play() { + if (!pipeline_ || error_occured_) + return; + if (play_rate_ == 0.0) { + playing_ = true; + return; + } +#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) + if (!audio_session_manager_->SetSoundState(ASM_STATE_PLAYING)) + return; +#endif + VLOG(1) << "MediaSourcePlayerGstreamer::" << __FUNCTION__ + << "Player ID:" << GetPlayerId(); + +#if defined(OS_TIZEN_MOBILE) && (defined(TIZEN_V_2_3) || defined(TIZEN_V_2_4)) + if (device_power_wakeup(false) != DEVICE_ERROR_NONE) + LOG(ERROR) << "|device_power_wakeup| request failed"; + + if (device_power_request_lock(POWER_LOCK_DISPLAY, 0) != DEVICE_ERROR_NONE) + LOG(ERROR) << "|device_power_request_lock| request failed"; +#endif + + gst_element_set_state(pipeline_, GST_STATE_PLAYING); + StartCurrentTimeUpdateTimer(); + playing_ = true; + is_paused_due_underflow_ = false; +} + +void MediaSourcePlayerGstreamer::Pause(bool is_media_related_action) { + if (!pipeline_ || error_occured_) + return; + +#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) + if (!audio_session_manager_->SetSoundState(ASM_STATE_PAUSE)) + return; +#endif + + VLOG(1) << "MediaSourcePlayerGstreamer::" << __FUNCTION__; + gst_element_set_state(pipeline_, GST_STATE_PAUSED); + + StopCurrentTimeUpdateTimer(); + if (!is_media_related_action) { + +#if defined(OS_TIZEN_MOBILE) && (defined(TIZEN_V_2_3) || defined(TIZEN_V_2_4)) + if (device_power_release_lock(POWER_LOCK_DISPLAY) != DEVICE_ERROR_NONE) + LOG(ERROR) << "|device_power_release_lock| request failed"; +#endif + + is_paused_due_underflow_ = false; + playing_ = false; + } +} + +void MediaSourcePlayerGstreamer::SetRate(double rate) { + VLOG(1) << "MediaSourcePlayerGstreamer::" + << __FUNCTION__ << " : " << rate; + + if (play_rate_ == rate) + return; + + if (rate == 0.0) { + play_rate_ = rate; + Pause(true); + return; + } + + // If rate was zero and requested rate is non-zero, change the paused state + if(play_rate_ == 0.0 && rate != 0.0) { + Play(); + StartCurrentTimeUpdateTimer(); + } + + play_rate_ = rate; + + RequestPlayerSeek(GetCurrentTime()); + +#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) + if (!audio_session_manager_->SetSoundState(ASM_STATE_PAUSE)) + return; +#endif +} + +void MediaSourcePlayerGstreamer::RequestPlayerSeek(double seekTime) { + VLOG(1) << "MediaSourcePlayerGstreamer::" << __FUNCTION__ + << " : " << seekTime; + if (is_demuxer_seeking_) + return; + GstState state; + gst_element_get_state(pipeline_, &state, NULL, 250 * GST_NSECOND); + is_demuxer_seeking_ = true; + if (state == GST_STATE_PLAYING) + Pause(true); + manager()->OnRequestSeek(GetPlayerId(), seekTime); +} + +void MediaSourcePlayerGstreamer::Seek(const double time) { + GstState state; + gst_element_get_state(pipeline_, &state, NULL, 250 * GST_NSECOND); + + is_seeking_iframe_ = false; + VLOG(1) << "MediaSourcePlayerGstreamer::" << __FUNCTION__ + << " : " << time << " state : " << gst_element_state_get_name(state); + + is_demuxer_seeking_ = true; + if (state == GST_STATE_PLAYING) + Pause(true); + + // Input to |FromMicroseconds| is |int64|. Additional multiplication + // is done to avoid data loss. + base::TimeDelta seek_time = base::TimeDelta::FromMicroseconds( + static_cast(time * base::Time::kMicrosecondsPerSecond)); + demuxer_->RequestDemuxerSeek(seek_time); +} + +void MediaSourcePlayerGstreamer::SeekInternal(const GstClockTime position) { + if (!pipeline_ || error_occured_) + return; + + GstClockTime startTime, endTime; + + is_demuxer_seeking_ = false; + + if (play_rate_ > 0) { + startTime = position; + endTime = GST_CLOCK_TIME_NONE; + } else { + startTime = 0; + endTime = position; + } + + VLOG(1) << "MediaSourcePlayerGstreamer::" << __FUNCTION__ + << " : " << position; + + UpdateSeekState(true); + audio_buffer_queue_.clear(); + video_buffer_queue_.clear(); + if(!gst_element_seek(pipeline_, play_rate_, GST_FORMAT_TIME, + static_cast(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), + GST_SEEK_TYPE_SET, startTime, GST_SEEK_TYPE_SET, endTime)) { + LOG(ERROR) << "Seek to " << position << " failed"; + HandleError(MediaPlayerEfl::NetworkStateDecodeError); + } +} + +double MediaSourcePlayerGstreamer::GetCurrentTime() { + if (!pipeline_ || error_occured_) + return 0.0; + + gint64 current_time = 0; + GstFormat format = GST_FORMAT_TIME; +#if GST_VERSION_MAJOR == 1 + gst_element_query_position(pipeline_, format, ¤t_time); +#else + gst_element_query_position(pipeline_, &format, ¤t_time); +#endif + return ConvertNanoSecondsToSeconds(current_time); +} + +void MediaSourcePlayerGstreamer::Release() { + VLOG(1) << "MediaSourcePlayerGstreamer::" << __FUNCTION__; + DCHECK(IsPlayerDestructing()); + playing_ = false; + StopCurrentTimeUpdateTimer(); + audio_buffer_queue_.clear(); + video_buffer_queue_.clear(); + + if (pipeline_) { + GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline_)); + if (bus) { + g_signal_handlers_disconnect_by_func( + bus, reinterpret_cast(gst_pipeline_message_cb), this); +#if GST_VERSION_MAJOR == 1 + gst_bus_set_sync_handler(bus, NULL, NULL, NULL); +#else + gst_bus_set_sync_handler(bus, NULL, NULL); +#endif + gst_object_unref(bus); + } + + gst_element_set_state(pipeline_, GST_STATE_NULL); + gst_object_unref(pipeline_); + pipeline_ = NULL; + } + + if (video_sink_pad_) + gst_object_unref(video_sink_pad_); + +#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) + if (!audio_session_manager_->SetSoundState(ASM_STATE_STOP)) + return; + if (!audio_session_manager_->DeallocateResources()) + return; +#endif +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + UnregisterDamageHandler(); + EflPixmapMap::iterator it = efl_pixmaps_map_.begin(); + while (it != efl_pixmaps_map_.end()) { + efl_pixmap_ = it->second; + if (efl_pixmap_.get()) + efl_pixmap_ = NULL; + it++; + } + efl_pixmaps_map_.clear(); +#endif +} + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +void MediaSourcePlayerGstreamer::UnregisterDamageHandler() { + if (m_damage) { + ecore_x_damage_free(m_damage); + m_damage = 0; + } + if (m_damageHandler) { + ecore_event_handler_del(m_damageHandler); + m_damageHandler = 0; + } +} +#endif + +void MediaSourcePlayerGstreamer::SetVolume(double volume) { + if (audio_volume_) + g_object_set(G_OBJECT(audio_volume_), "volume", volume, NULL); +} + +void MediaSourcePlayerGstreamer::OnDemuxerConfigsAvailable( + const DemuxerConfigs& configs) { + if (IsPlayerDestructing()) + return; + + if ((configs.video_codec == kUnknownVideoCodec || + configs.video_codec != kCodecH264) && + (configs.audio_codec == kUnknownAudioCodec || + (configs.audio_codec != kCodecAAC && + configs.audio_codec != kCodecMP3))) { + LOG(ERROR) << "Audio and Video codecs not supported for MediaSource"; + HandleError(MediaPlayerEfl::NetworkStateFormatError); + return; + } + + gst_width_ = configs.video_size.width(); + gst_height_ = configs.video_size.height(); + + if (is_gst_pipeline_constructed_) { + return; + } + is_gst_pipeline_constructed_ = true; + + GError* err = NULL; + if (!gst_is_initialized()) { + gst_init_check(NULL, NULL, &err); + } + + if (gst_is_initialized() && !err) { + pipeline_ = gst_pipeline_new(kPipelineName); + if (!pipeline_) { + LOG(ERROR) << "Unable to Create |Pipeline|"; + HandleError(MediaPlayerEfl::NetworkStateDecodeError); + return; + } + + int i = 0; + while (VideoMapping[i].codec != kUnknownVideoCodec) { + if (configs.video_codec == VideoMapping[i].codec) { + media_type |= MEDIA_VIDEO_MASK; + video_appsrc_ = gst_element_factory_make("appsrc", "video-source"); + video_parse_ = gst_element_factory_make(VideoMapping[i].elements[0], + "video-parse"); + video_queue_ = gst_element_factory_make("queue2", "video-queue"); + video_decoder_ = gst_element_factory_make(VideoMapping[i].elements[1], + "video-decoder"); + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + PrepareForVideoSink(); +#else + PrepareForVideoFrame(); +#endif + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + if (is_backed_by_pixmap) + CreatePixmap(); +#endif + if (!video_appsrc_ || !video_parse_ || !video_queue_ || + !video_decoder_ || !video_sink_) { + LOG(ERROR) << "Not all elements of video pipeline could be created"; + ReleaseVideoElements(); + HandleError(MediaPlayerEfl::NetworkStateDecodeError); + return; + } + + g_object_set(GST_OBJECT(video_appsrc_), "format", GST_FORMAT_TIME, NULL); + g_object_set(GST_OBJECT(video_appsrc_), "stream-type", + GST_APP_STREAM_TYPE_SEEKABLE, NULL); + g_object_set(GST_OBJECT(video_appsrc_), "do-timestamp", false, NULL); + + // Will make the queue to send GST_MESSAGE_BUFFERING + g_object_set(G_OBJECT(video_queue_), "use-buffering", true, NULL); + + // Will trigger need-data callback if buffer goes below 30%, + // default is 10%. Data type of property "low-percent" differs + // on desktop and TIZEN platform. +#if GST_VERSION_MAJOR < 1 + g_object_set(G_OBJECT(video_queue_), "low-percent", (double)30.0, NULL); +#else + g_object_set(G_OBJECT(video_queue_), "low-percent", 30, NULL); +#endif + + gst_bin_add_many(GST_BIN(pipeline_), video_appsrc_, video_queue_, + video_parse_, video_decoder_, video_sink_, NULL); + + // Why |video_queue_| is placed after |video_appsrc_|? + // For understanding puprose consider http://tinyurl.com/qos-iron url. + // For 1080p resolution of the video in above url, each decoded frame + // is of size 2304000 bytes ~ 2.19 MB. If video_queue_ is placed before + // |video_sink_| then queue will buffer decoded frames, so to buffer + // two second worth of data queue will require 2304000*24(fps)*2 ~ 96MB + // of queue size. This property can't be set for pixmap backed playback + // as frame size won't be available for pixmap backed | video_sink|. + // And this size varies from video to video. + // + // But if |video_queue_| is placed after |video_appsrc_|, queue will + // buffer encoded data. For the same video of 1080p, maximum encoded + // frame is of 115398byte ~ 0.110052109 MB. So for 2 sec data, queue + // need to buffer 5308308bytes in queue ~ 5MB, this can be set + // dynamically. Refer |OnDemuxerDataAvailable| for setting queue size. + + gst_element_link_many(video_appsrc_,video_queue_, video_parse_, + video_decoder_, video_sink_, NULL); + static GstAppSrcCallbacks video_callbacks = { + on_gst_start_video_feed_cb, + on_gst_stop_video_feed_cb, + on_gst_seek_video_feed_cb, {NULL}}; + + // FIXME: Try fourth argument for destructy notification. + gst_app_src_set_callbacks(GST_APP_SRC(video_appsrc_), &video_callbacks, + this, NULL); + break; + } + i++; + } + + i = 0; + while (AudioMapping[i].codec != kUnknownAudioCodec) { + if(configs.audio_codec == AudioMapping[i].codec) { + media_type |= MEDIA_AUDIO_MASK; + audio_appsrc_ = gst_element_factory_make("appsrc", "audio-source"); + audio_queue_ = gst_element_factory_make("queue2", "audio-queue"); + audio_parse_ = gst_element_factory_make(AudioMapping[i].elements[0], + "audio-parse"); + audio_decoder_ = gst_element_factory_make(AudioMapping[i].elements[1], + "audio-decoder"); + audio_convert_ = gst_element_factory_make("audioconvert", "audio-convert"); + audio_resampler_ = gst_element_factory_make( + "audioresample", "audio-resample"); + audio_volume_ = gst_element_factory_make("volume", "volume"); + audio_sink_ = gst_element_factory_make( + AudioMapping[i].elements[2], "audio-sink"); + + if (!audio_appsrc_ || !audio_queue_ || !audio_parse_ || + !audio_decoder_ || !audio_convert_ || !audio_resampler_ || + !audio_volume_ || !audio_sink_) { + LOG(ERROR) << "Not all elements of audio pipeline could be created"; + ReleaseAudioElements(); + HandleError(MediaPlayerEfl::NetworkStateDecodeError); + return; + } + + g_object_set( + GST_OBJECT(audio_appsrc_),"format", GST_FORMAT_TIME, NULL); + g_object_set(GST_OBJECT(audio_appsrc_),"stream-type", + GST_APP_STREAM_TYPE_SEEKABLE, NULL); + g_object_set(GST_OBJECT(audio_appsrc_), "do-timestamp", false, NULL); + + g_object_set(G_OBJECT(audio_queue_), "use-buffering", true, NULL); + +#if GST_VERSION_MAJOR < 1 + g_object_set( + G_OBJECT(audio_queue_), "low-percent", (double)30.0, NULL); +#else + g_object_set(G_OBJECT(audio_queue_), "low-percent", 30, NULL); +#endif + + g_object_set(G_OBJECT(audio_volume_), "mute", false, NULL); + +#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) + if (!audio_session_manager_->AllocateResources(audio_decoder_)) + return; + + g_object_set(audio_sink_, "provide-clock", true, "device", "hw:0,0", NULL); + if (!audio_session_manager_->AllocateResources(audio_sink_)) + return; +#endif + + gst_bin_add_many(GST_BIN(pipeline_), audio_appsrc_, audio_queue_, + audio_parse_, audio_decoder_, audio_convert_, audio_resampler_, + audio_volume_, audio_sink_, NULL); + + gst_element_link_many(audio_appsrc_, audio_queue_, audio_parse_, + audio_decoder_, audio_convert_, audio_resampler_, audio_volume_, + audio_sink_, NULL); + + static GstAppSrcCallbacks audio_callbacks = { + on_gst_start_audio_feed_cb, + on_gst_stop_audio_feed_cb, + on_gst_seek_audio_feed_cb, {NULL}}; + + gst_app_src_set_callbacks(GST_APP_SRC(audio_appsrc_), &audio_callbacks, + this, NULL); + break; + } + i++; + } + + GstBus*bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline_)); + if (!bus) { + LOG(ERROR) << "GStreamer bus creation failed"; + HandleError(MediaPlayerEfl::NetworkStateDecodeError); + return; + } +#if GST_VERSION_MAJOR == 1 + gst_bus_set_sync_handler( + bus, (GstBusSyncHandler)gst_pipeline_message_cb, this, NULL); +#else + gst_bus_set_sync_handler( + bus, (GstBusSyncHandler)gst_pipeline_message_cb, this); +#endif + gst_object_unref(bus); + + manager()->OnMediaDataChange(GetPlayerId(), video_format_, + gst_height_, gst_width_, media_type); + + manager()->OnReadyStateChange(GetPlayerId(), + MediaPlayerEfl::ReadyStateHaveMetadata); + + if (gst_element_set_state(pipeline_, GST_STATE_PAUSED) == + GST_STATE_CHANGE_FAILURE) + LOG(ERROR) << "GStreamer state change failed"; + } else { + LOG(ERROR) << "Unable to initialize GST"; + HandleError(MediaPlayerEfl::NetworkStateDecodeError); + } +} + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +void MediaSourcePlayerGstreamer::PrepareForVideoSink() { + video_sink_ = gst_element_factory_make("xvimagesink", "sink"); + if ( video_sink_ == NULL) { + PrepareForVideoFrame(); + } else { + VLOG(1) << "MediaSource using |xvimagesink| for Video Playback"; + is_backed_by_pixmap = true; + video_sink_pad_ = gst_element_get_static_pad(video_sink_, "sink"); + if (video_sink_pad_) { + g_signal_connect(video_sink_pad_, "notify::caps", + G_CALLBACK(on_video_sink_caps_changed_cb), this); + } else { + LOG(ERROR) << " |video_sink_pad_| is NULL ?"; + } + } +} +#endif + +void MediaSourcePlayerGstreamer::PrepareForVideoFrame() { + is_xwindow_handle_set_ = true; + VLOG(1) << "MediaSource using |appsink| for Video Playback"; + video_sink_ = gst_element_factory_make("appsink", "sink"); +#if GST_VERSION_MAJOR == 1 + GstAppSinkCallbacks callbacks = {NULL, on_gst_appsink_preroll, + on_gst_appsink_sample}; +#else + GstAppSinkCallbacks callbacks = {NULL, + on_gst_appsink_preroll, + on_gst_appsink_sample, + NULL, + {NULL, NULL, NULL}}; +#endif + gst_app_sink_set_callbacks(GST_APP_SINK(video_sink_), &callbacks, this, + NULL); + g_object_set(G_OBJECT(video_sink_), "max-buffers", (guint)1, NULL); +} + +void MediaSourcePlayerGstreamer::ReadDemuxedData( + media::DemuxerStream::Type type) { + if (IsPlayerDestructing()) + return; + + if (type == media::DemuxerStream::AUDIO) { + should_feed_audio_ = true; + } else if (type == media::DemuxerStream::VIDEO) { + should_feed_video_ = true; + } else { + LOG(ERROR) << "Unknown Media Type in MediaSourcePlayerGstreamer::" + << __FUNCTION__; + return; + } + demuxer_->RequestDemuxerData(type); +} + +void MediaSourcePlayerGstreamer::OnReadDemuxedData( + media::DemuxerStream::Type type) { + if (IsPlayerDestructing()) { + LOG(ERROR) << __FUNCTION__ << "GST is deinitializing. Just return"; + return; + } + main_loop_->PostTask(FROM_HERE, base::Bind( + &MediaSourcePlayerGstreamer::ReadDemuxedData, base::Unretained(this), + type)); +} + +void MediaSourcePlayerGstreamer::OnStopDemuxedData( + media::DemuxerStream::Type type) { + if (type == media::DemuxerStream::AUDIO) + should_feed_audio_ = false; + else if (type == media::DemuxerStream::VIDEO) + should_feed_video_ = false; + else + LOG(ERROR) << "Unknown Media Type in MediaSourcePlayerGstreamer::" + << __FUNCTION__; +} + +void MediaSourcePlayerGstreamer::OnDemuxerDataAvailable( + base::SharedMemoryHandle foreign_memory_handle, + const media::DemuxedBufferMetaData& meta_data) { + if (!pipeline_ || error_occured_) { + LOG(ERROR) << "Pipeline_ null or error occured"; + return; + } + if (meta_data.size <= 0) { + LOG(ERROR) << "ERROR : Size of shared memory is Zero"; + return; + } + + if (is_seeking_ && !is_seeking_iframe_) { + if (meta_data.type == media::DemuxerStream::VIDEO) { + is_seeking_iframe_ = true; + if (video_seek_offset_ > + (guint64)(meta_data.timestamp.InMicroseconds() * 1000)) { + RequestPlayerSeek((double)(ConvertNanoSecondsToSeconds( + meta_data.timestamp.InMicroseconds() * 1000 + + kSixteenMilliSeconds))); + return; + } + } else if (meta_data.type == media::DemuxerStream::AUDIO) { + if ( audio_seek_offset_ > + (guint64)(meta_data.timestamp.InMicroseconds() * 1000)) + return; + } + } + + ReadFromQueueIfAny(meta_data.type); + if (meta_data.type == media::DemuxerStream::VIDEO) { + if (meta_data.size > raw_video_frame_size_) { + // Dynamically Changing Video Queue Size for Smooth Playback. + // The default queue size limits are 100 buffers, 2MB of data, + // or two seconds worth of data, whichever is reached first. + // Adjust queue to contain two seconds worth of data for smooth playback. + // So need to adjust number of buffers (max-size-buffers >= 2*fps) and + // maximum size of queue (max-size-bytes >= 2*fps*meta_data.size). + // + // 1000000 micro seconds = 1 second. + // 2097152 bytes = 2 MB. + int no_frames_per_two_second , queue_size_for_two_sec; + raw_video_frame_size_ = meta_data.size; + no_frames_per_two_second = 2 * (1000000 / + (meta_data.time_duration.InMicroseconds())); + queue_size_for_two_sec = + raw_video_frame_size_ * no_frames_per_two_second; + if (no_frames_per_two_second > 100) { + g_object_set(G_OBJECT(video_queue_), "max-size-buffers", + no_frames_per_two_second, NULL); + } + if (queue_size_for_two_sec > 2097152) { + g_object_set(G_OBJECT(video_queue_), "max-size-bytes", + queue_size_for_two_sec, NULL); + } + } + } + if (meta_data.type == media::DemuxerStream::AUDIO && !should_feed_audio_) { + // Why store the DecoderBuffer? we have requested for buffer + // from demuxer but gstreamer asked to stop. So need to save + // this buffer and use it on next |need_data| call. + SaveDecoderBuffer(foreign_memory_handle, meta_data); + return; + } + if (meta_data.type == media::DemuxerStream::VIDEO && !should_feed_video_) { + SaveDecoderBuffer(foreign_memory_handle, meta_data); + return; + } + + base::SharedMemory shared_memory(foreign_memory_handle, false); + shared_memory.Map(meta_data.size); + void* ptr; + gint size = meta_data.size; + GstFlowReturn ret = GST_FLOW_OK; + ptr = g_malloc(size); + memcpy(ptr, shared_memory.memory(), size); + +#if GST_VERSION_MAJOR == 1 + GstBuffer* buffer = gst_buffer_new_allocate(NULL, meta_data.size, NULL); + gst_buffer_fill (buffer, 0, ptr, meta_data.size); +#else + GstBuffer* buffer = gst_buffer_new(); + GST_BUFFER_MALLOCDATA(buffer) = (uint8*)ptr; + GST_BUFFER_SIZE(buffer) = size; + GST_BUFFER_DATA(buffer) = GST_BUFFER_MALLOCDATA(buffer); +#endif + GST_BUFFER_TIMESTAMP (buffer) = + (guint64)(meta_data.timestamp.InMicroseconds() * 1000); + GST_BUFFER_DURATION (buffer) = + (guint64)(meta_data.time_duration.InMicroseconds() * 1000); + + if (meta_data.type == media::DemuxerStream::AUDIO) + ret = gst_app_src_push_buffer(GST_APP_SRC(audio_appsrc_), buffer); + else if (meta_data.type == media::DemuxerStream::VIDEO) + ret = gst_app_src_push_buffer(GST_APP_SRC(video_appsrc_), buffer); + + // gst_app_src_push_buffer() takes ownership of the buffer. + // Hence no need to unref buffer. + if (ret != GST_FLOW_OK) { + LOG(ERROR) << __FUNCTION__ << " : Gstreamer appsrc push failed : " << ret; + shared_memory.Close(); + return; + } + + if (meta_data.type == media::DemuxerStream::AUDIO && should_feed_audio_) + OnReadDemuxedData(media::DemuxerStream::AUDIO); + else if (meta_data.type == media::DemuxerStream::VIDEO && should_feed_video_) + OnReadDemuxedData(media::DemuxerStream::VIDEO); + shared_memory.Close(); + return; +} + +void MediaSourcePlayerGstreamer::OnBufferMetaDataAvailable( + const media::DemuxedBufferMetaData& meta_data) { + + if (!pipeline_ || error_occured_) { + LOG(ERROR) << "Pipeline_ null or error occured"; + return; + } + + switch (meta_data.status) { + case media::DemuxerStream::kAborted: + // FIXME : Need to handle Aborted state Properly. + if (meta_data.type == media::DemuxerStream::AUDIO && should_feed_audio_) + OnReadDemuxedData(media::DemuxerStream::AUDIO); + else if (meta_data.type == media::DemuxerStream::VIDEO && + should_feed_video_) + OnReadDemuxedData(media::DemuxerStream::VIDEO); + break; + + case media::DemuxerStream::kConfigChanged: + if (meta_data.type == media::DemuxerStream::AUDIO && should_feed_audio_) + OnReadDemuxedData(media::DemuxerStream::AUDIO); + else if (meta_data.type == media::DemuxerStream::VIDEO && + should_feed_video_) + OnReadDemuxedData(media::DemuxerStream::VIDEO); + + if (meta_data.type == media::DemuxerStream::AUDIO) + VLOG(1) << "[BROWSER] : AUDIO::kConfigChanged"; + if (meta_data.type == media::DemuxerStream::VIDEO) + VLOG(1) << "[BROWSER] : VIDEO::kConfigChanged"; + break; + + case media::DemuxerStream::kOk: + if (meta_data.end_of_stream) { + ReadFromQueueIfAny(meta_data.type); + LOG(ERROR) <<"[BROWSER] : DemuxerStream::kOk but |end_of_stream|"; + if (meta_data.type == media::DemuxerStream::AUDIO) + gst_app_src_end_of_stream(GST_APP_SRC(audio_appsrc_)); + if (meta_data.type == media::DemuxerStream::VIDEO) + gst_app_src_end_of_stream(GST_APP_SRC(video_appsrc_)); + if (playing_) + Play(); + } + break; + + default: + NOTREACHED(); + } +} + +void MediaSourcePlayerGstreamer::ReadFromQueueIfAny( + DemuxerStream::Type type) { + if (!pipeline_ || error_occured_) { + LOG(ERROR) << "Pipeline_ null or error occured"; + return; + } + + if (type == media::DemuxerStream::AUDIO) { + if (audio_buffer_queue_.empty() || !should_feed_audio_) + return; + } + + if (type == media::DemuxerStream::VIDEO) { + if (video_buffer_queue_.empty() || !should_feed_video_) + return; + } + + scoped_refptr decoder_buffer; + if (type == media::DemuxerStream::AUDIO) { + decoder_buffer = audio_buffer_queue_.front(); + audio_buffer_queue_.pop_front(); + } else { + decoder_buffer = video_buffer_queue_.front(); + video_buffer_queue_.pop_front(); + } + + void* ptr; + GstFlowReturn ret; + gint size = decoder_buffer.get()->data_size(); + ptr = g_malloc(size); + memcpy(ptr, (void*)decoder_buffer.get()->writable_data(), size); +#if GST_VERSION_MAJOR == 1 + GstBuffer* buffer = gst_buffer_new_allocate(NULL, size, NULL); + gst_buffer_fill (buffer, 0, ptr, size); +#else + GstBuffer* buffer = gst_buffer_new(); + GST_BUFFER_MALLOCDATA(buffer) = (uint8*)ptr; + GST_BUFFER_SIZE(buffer) = size; + GST_BUFFER_DATA(buffer) = GST_BUFFER_MALLOCDATA(buffer); +#endif + GST_BUFFER_TIMESTAMP (buffer) = + (guint64)(decoder_buffer.get()->timestamp().InMicroseconds() * 1000); + GST_BUFFER_DURATION (buffer) = + (guint64)(decoder_buffer.get()->duration().InMicroseconds() * 1000); + + if (type == media::DemuxerStream::AUDIO) + ret = gst_app_src_push_buffer(GST_APP_SRC(audio_appsrc_), buffer); + else + ret = gst_app_src_push_buffer(GST_APP_SRC(video_appsrc_), buffer); + if (ret != GST_FLOW_OK) + return; + + //Empty the Buffer before reading the new buffer from render process. + ReadFromQueueIfAny(type); + return; +} + +void MediaSourcePlayerGstreamer::SaveDecoderBuffer( + base::SharedMemoryHandle foreign_memory_handle, + const media::DemuxedBufferMetaData& meta_data) { + if (!pipeline_ || error_occured_) { + LOG(ERROR) << "Pipeline_ null or error occured"; + return; + } + + base::SharedMemory shared_memory(foreign_memory_handle, false); + shared_memory.Map(meta_data.size); + scoped_refptr buffer; + buffer = DecoderBuffer::CopyFrom(static_cast ( + shared_memory.memory()), meta_data.size); + + if (!buffer.get()) { + LOG(ERROR) << "DecoderBuffer::CopyFrom failed"; + shared_memory.Close(); + return; + } + + buffer->set_timestamp(meta_data.timestamp); + buffer->set_duration(meta_data.time_duration); + + if (meta_data.type == media::DemuxerStream::AUDIO) + audio_buffer_queue_.push_back(buffer); + else + video_buffer_queue_.push_back(buffer); + + shared_memory.Close(); +} + +void MediaSourcePlayerGstreamer::GetFrameDetails() { + if (!pipeline_ || error_occured_) + return; + + GstState state; + GstState pending; + GstStateChangeReturn ret = gst_element_get_state(pipeline_, + &state, &pending, 250 * GST_NSECOND); + VLOG(1) << "MediaSourcePlayerGstreamer::" + << __FUNCTION__ + << " GstStateChangeReturn: " + << gst_element_state_change_return_get_name(ret) + << " state: " + << gst_element_state_get_name(state) + << " pending: " + << gst_element_state_get_name(pending) + << " ID " << GetPlayerId(); + + // Get details only after prerolling. + if (pending >= GST_STATE_PAUSED) + main_loop_->PostTask(FROM_HERE, base::Bind( + &MediaSourcePlayerGstreamer::OnGetFrameDetails, + base::Unretained(this))); +} + +void MediaSourcePlayerGstreamer::OnGetFrameDetails() { + if (!pipeline_ || IsPlayerDestructing() || error_occured_) + return; +#if GST_VERSION_MAJOR == 1 + GstSample* sample = gst_app_sink_pull_preroll(GST_APP_SINK(video_sink_)); + if (!sample) + return; + + GstCaps* caps = gst_sample_get_caps(sample); + if (!caps) + return; + + GstVideoInfo vi; + gst_video_info_from_caps(&vi, caps); + + gst_width_ = GST_VIDEO_INFO_WIDTH(&vi); + gst_height_ = GST_VIDEO_INFO_HEIGHT(&vi); + switch(GST_VIDEO_INFO_FORMAT(&vi)) { + case GST_VIDEO_FORMAT_I420:{ + video_format_ = GST_MAKE_FOURCC('I','4','2','0'); + break; + } + case GST_VIDEO_FORMAT_NV12:{ + video_format_ = GST_MAKE_FOURCC('N','V','1','2'); + break; + } + default: + LOG(ERROR) << "Unknown format : " << GST_VIDEO_INFO_FORMAT(&vi); + break; + } +#else + + GstBuffer* sample = gst_app_sink_pull_preroll(GST_APP_SINK(video_sink_)); + + if (!sample) + return; + GstCaps* caps = gst_buffer_get_caps(GST_BUFFER(sample)); + if (!caps) { + gst_buffer_unref(sample); + return; + } + + // No need to unref |GstStructure| + const GstStructure* str = gst_caps_get_structure(caps, 0); + gst_caps_unref(caps); + gst_buffer_unref(sample); + if (!str) + return; + + if (!gst_structure_get_int(str, "width", &gst_width_) || + !gst_structure_get_int(str, "height", &gst_height_) || + !gst_structure_get_fourcc(str, "format", &video_format_)) { + LOG(ERROR) << "Pre-rolled sample information could not be obtained"; + } +#endif + + if(video_format_ == GST_VIDEO_SN12) { + uint tile_w_align = ((gst_width_ - 1) / SN12_TILE_WIDTH + 2) & ~1; + bufsize_sn12_ = + SN12_TILE_SIZE * tile_w_align * ((gst_height_-1)/SN12_TILE_HEIGHT+1) + + (((gst_height_+1)&~1)/2) * tile_w_align * SN12_TILE_WIDTH; + } + manager()->OnMediaDataChange(GetPlayerId(), video_format_, + gst_height_, gst_width_, media_type); +} + +#if GST_VERSION_MAJOR == 1 +GstSample* MediaSourcePlayerGstreamer::PullSample() { + return gst_app_sink_pull_sample(GST_APP_SINK(video_sink_)); +} + +void MediaSourcePlayerGstreamer::OnNewFrameAvailable(GstSample* sample) { + if (!pipeline_ || error_occured_) + return; + + GstMapInfo map; + GstBuffer* buffer = gst_sample_get_buffer(sample); + if (!gst_buffer_map(buffer, &map, GST_MAP_READ)) { + LOG (ERROR) << "Sample contains invalid or no info!"; + return; + } + + if (!gst_width_ || !gst_height_) + GetFrameDetails(); + + GstCaps* caps = gst_sample_get_caps(sample); + if (caps) { + GstVideoInfo vi; + gst_video_info_from_caps(&vi, caps); + int width = GST_VIDEO_INFO_WIDTH(&vi); + int height = GST_VIDEO_INFO_HEIGHT(&vi); + + if (width != gst_width_|| height != gst_height_) { + LOG (INFO) << __FUNCTION__ + << " ###### from " << gst_width_ << "X" << gst_height_ + << " to " << width << "X" << height; + gst_width_ = width; + gst_height_ = height; + manager()->OnMediaDataChange( + GetPlayerId(), video_format_, gst_height_, gst_width_, media_type); + } + } + + base::TimeDelta timestamp = + base::TimeDelta::FromMicroseconds( + GST_BUFFER_TIMESTAMP(buffer) / + base::Time::kNanosecondsPerMicrosecond); + + if(video_format_ == GST_VIDEO_SN12) + shared_memory_size = (bufsize_sn12_); + else + shared_memory_size = (map.size); + + if (!shared_memory.CreateAndMapAnonymous(shared_memory_size)) { + LOG (ERROR) << "Shared Memory creation failed."; + gst_buffer_unmap(buffer, &map); + gst_sample_unref(sample); + return; + } + + if (!shared_memory.ShareToProcess(base::Process::Current().Handle(), + &foreign_memory_handle)) { + LOG (ERROR) << "Shared Memory handle could not be obtained"; + shared_memory.Close(); + gst_buffer_unmap(buffer, &map); + gst_sample_unref(sample); + return; + } + + memcpy(shared_memory.memory(), map.data, shared_memory_size); + manager()->OnNewFrameAvailable( + GetPlayerId(), foreign_memory_handle, shared_memory_size, timestamp); + + shared_memory.Close(); + gst_buffer_unmap(buffer, &map); + gst_sample_unref(sample); +} +#else +GstBuffer* MediaSourcePlayerGstreamer::PullSample() { + return gst_app_sink_pull_buffer(GST_APP_SINK(video_sink_)); +} + +void MediaSourcePlayerGstreamer::OnNewFrameAvailable(const GstBuffer* buffer) { + if (!pipeline_ || error_occured_) + return; + if (!buffer) + return; + if (!GST_BUFFER_DATA(buffer) || !GST_BUFFER_SIZE(buffer)) + return; + + if (!gst_width_ || !gst_height_) + GetFrameDetails(); + // FIXME: Cross check the end results. + base::TimeDelta timestamp = + base::TimeDelta::FromMicroseconds( + GST_BUFFER_TIMESTAMP(buffer) / + base::Time::kNanosecondsPerMicrosecond); + + uint8* buffer_data = GST_BUFFER_DATA(buffer); + gsize buffer_size = GST_BUFFER_SIZE(buffer); + + if(video_format_ == GST_VIDEO_SN12) + shared_memory_size = (bufsize_sn12_); + else + shared_memory_size = (buffer_size); + + if (!shared_memory.CreateAndMapAnonymous(shared_memory_size)) { + LOG (ERROR) << "Shared Memory creation failed."; + gst_buffer_unref(GST_BUFFER(buffer)); + return; + } + + if (!shared_memory.ShareToProcess(base::Process::Current().Handle(), + &foreign_memory_handle)) { + LOG (ERROR) << "Shared Memory handle could not be obtained"; + shared_memory.Close(); + gst_buffer_unref(GST_BUFFER(buffer)); + return; + } + + memcpy(shared_memory.memory(), buffer_data, shared_memory_size); + manager()->OnNewFrameAvailable( + GetPlayerId(), foreign_memory_handle, shared_memory_size, timestamp); + + shared_memory.Close(); + gst_buffer_unref(GST_BUFFER(buffer)); +} +#endif + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +void MediaSourcePlayerGstreamer::XWindowIdPrepared(GstMessage* message) { + gint width, height; +#if GST_VERSION_MAJOR == 1 + const GstStructure* structure = gst_message_get_structure(message); + + gst_structure_get_int(structure, "video-width", &width); + gst_structure_get_int(structure, "video-height", &height); +#else + gst_structure_get_int(message->structure, "video-width", &width); + gst_structure_get_int(message->structure, "video-height", &height); +#endif + if ((gst_width_ != width) || (gst_height_ != height)) { + LOG(ERROR) << "Demuxer Video Configs and Gstreamer Video Configs doesn't" + <<" match.From Demuxer : width : "<OnMediaDataChange( + GetPlayerId(), video_format_, gst_height_, gst_width_, media_type); +} + +void MediaSourcePlayerGstreamer::PlatformSurfaceUpdated() { + gint64 current_time = 0; + GstFormat format = GST_FORMAT_TIME; +#if GST_VERSION_MAJOR == 1 + gst_element_query_position(pipeline_, format, ¤t_time); +#else + gst_element_query_position(pipeline_, &format, ¤t_time); +#endif + base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds( + current_time / base::Time::kNanosecondsPerMicrosecond); + manager()->OnPlatformSurfaceUpdated(GetPlayerId(), pixmap_id_, timestamp); +} + +int MediaSourcePlayerGstreamer::GetSurfaceID() const { + return pixmap_id_; +} + +void MediaSourcePlayerGstreamer::SetPixmap() { +#if GST_VERSION_MAJOR == 1 + gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(video_sink_), pixmap_id_); +#else +#if defined(OS_TIZEN_TV) + // Using below statements on mobile to set pixmap was causing two issue. + // 1. Video size was different than the required one whenever configaration + // changed + // 2. Sometime black screen was appearing, while video was playing. + // Hence for mobile keeping implementation which uses + // |gst_x_overlay_set_window_handle|to sep Pixmap. + g_object_set (video_sink_, "pixmap-id-callback", get_pixmap_id_cb, NULL); + g_object_set (video_sink_, "pixmap-id-callback-userdata", this, NULL); +#else + gst_x_overlay_set_window_handle(GST_X_OVERLAY(video_sink_), pixmap_id_); +#endif +#endif + m_damage = ecore_x_damage_new(pixmap_id_, + ECORE_X_DAMAGE_REPORT_RAW_RECTANGLES); + m_damageHandler = ecore_event_handler_add(ECORE_X_EVENT_DAMAGE_NOTIFY, + notify_damage_updated_cb, this); + g_object_set(video_sink_, "rotate", 0, NULL); + is_xwindow_handle_set_ = true; +} + +void MediaSourcePlayerGstreamer::OnVideoConfigsChanged() { + if (!pipeline_ || error_occured_) + return; + main_loop_->PostTask(FROM_HERE, base::Bind( + &MediaSourcePlayerGstreamer::VideoConfigsChanged, + base::Unretained(this))); +} + +void MediaSourcePlayerGstreamer::VideoConfigsChanged() { + if (!pipeline_ || IsPlayerDestructing() || error_occured_) + return; + VLOG(1) << "Video Configs Changed, so changing the pixmap"; + gint width, height; + +#if GST_VERSION_MAJOR == 1 + GstCaps* caps = gst_pad_get_current_caps(GST_PAD(video_sink_pad_)); + if (caps) { + GstVideoInfo info; + gst_video_info_init(&info); + + if (gst_video_info_from_caps(&info, caps)) { + width = info.width; + height = info.height; + } + } +#else + if (gst_video_get_size(video_sink_pad_, &width, &height)) { + LOG(ERROR) << "Cannot get width / height!"; + return; + } +#endif + if ((gst_width_ != width) || (gst_height_ != height)) { + LOG(ERROR) << "Demuxer Video Configs and Gstreamer Video Configs doesn't" + <<" match.From Demuxer : width : "<OnMediaDataChange( + GetPlayerId(), video_format_, gst_height_, gst_width_, media_type); + } +} + +void MediaSourcePlayerGstreamer::CreatePixmap() { + bool is_create_new = false; + std::string string_wh = + ConvertWidthAndHeightToString(gst_width_, gst_height_); + if (efl_pixmaps_map_.size() == 0) + is_create_new = true; + + if (!is_create_new) { + EflPixmapMap::iterator it = efl_pixmaps_map_.find(string_wh); + if (it != efl_pixmaps_map_.end()) { + is_create_new = false; + efl_pixmap_ = it->second; + pixmap_id_ = efl_pixmap_->GetId(); + } else { + is_create_new = true; + } + } + + if (is_create_new) { + efl_pixmap_ = gfx::EflPixmap::Create(gfx::EflPixmap::SURFACE, + gfx::Size(gst_width_, gst_height_)); + if (!efl_pixmap_.get()) { + LOG(ERROR) << "gfx::EflPixmap::Create() failed to create Pixmap"; + return; + } + pixmap_id_ = efl_pixmap_->GetId(); + efl_pixmaps_map_[string_wh] = efl_pixmap_; + } +} +#endif + +void MediaSourcePlayerGstreamer::OnDemuxerDurationChanged( + base::TimeDelta duration) { + duration_ = duration.InSecondsF(); +} + +void MediaSourcePlayerGstreamer::OnDemuxerSeekDone( + const base::TimeDelta& actual_browser_seek_time) { + VLOG(1) << "MediaSourcePlayerGstreamer::" << __FUNCTION__ << " : " + << actual_browser_seek_time.InSecondsF(); + SeekInternal(ConvertToGstClockTime(actual_browser_seek_time.InSecondsF())); +} + +bool MediaSourcePlayerGstreamer::HasVideo() { + return media_type & MEDIA_VIDEO_MASK; +} + +bool MediaSourcePlayerGstreamer::HasAudio() { + return media_type & MEDIA_AUDIO_MASK; +} + +void MediaSourcePlayerGstreamer::OnCurrentTimeUpdateTimerFired() { + manager()->OnTimeUpdate(GetPlayerId(), GetCurrentTime()); +} + +void MediaSourcePlayerGstreamer::StartCurrentTimeUpdateTimer() { + if (!current_time_update_timer_.IsRunning()) { + current_time_update_timer_.Start( + FROM_HERE, + base::TimeDelta::FromMilliseconds(kDurationUpdateInterval), + this, &MediaSourcePlayerGstreamer::OnCurrentTimeUpdateTimerFired); + } +} + +void MediaSourcePlayerGstreamer::StopCurrentTimeUpdateTimer() { + if (current_time_update_timer_.IsRunning()) + current_time_update_timer_.Stop(); +} + +void MediaSourcePlayerGstreamer::HandleMessage(GstMessage* message) { + if (!pipeline_ || error_occured_) + return; + if (!strcmp(kPipelineName, GST_MESSAGE_SRC_NAME(message))) + VLOG(1) << "MediaSourcePlayerGstreamer::" << __FUNCTION__ + << " Message " << GST_MESSAGE_TYPE_NAME(message) + << " received from element " << GST_MESSAGE_SRC_NAME(message) + << " ID " << GetPlayerId(); + + switch (GST_MESSAGE_TYPE(message)) { + case GST_MESSAGE_ELEMENT: +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + if (!IsXWindowHadleSet() && +#if GST_VERSION_MAJOR == 1 + gst_is_video_overlay_prepare_window_handle_message(message)) { +#else + message->structure && + gst_structure_has_name(message->structure, "prepare-xid")) { +#endif + LOG(INFO) << "Received message : Video overlay prepared"; + XWindowIdPrepared(message); + return; + } +#endif + case GST_MESSAGE_ERROR: + GError* error; + gst_message_parse_error(message, &error, NULL); + MediaPlayerEfl::NetworkState network_state_error; + network_state_error = MediaPlayerEfl::NetworkStateEmpty; + if (error->code == GST_STREAM_ERROR_CODEC_NOT_FOUND + || error->code == GST_STREAM_ERROR_WRONG_TYPE + || error->code == GST_STREAM_ERROR_FAILED + || error->code == GST_RESOURCE_ERROR_NOT_FOUND) { + network_state_error = MediaPlayerEfl::NetworkStateFormatError; + } else if (error->domain == GST_RESOURCE_ERROR) { + network_state_error = MediaPlayerEfl::NetworkStateNetworkError; + } else { + network_state_error = MediaPlayerEfl::NetworkStateDecodeError; + } +#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) + if (!audio_session_manager_->SetSoundState(ASM_STATE_STOP)) + return; + if (!audio_session_manager_->DeallocateResources()) + return; +#endif + LOG(ERROR) << "Error Message : " << error->message << " Recieved From : " + << GST_MESSAGE_SRC_NAME(message) + << ", and Blink Error Code = " << network_state_error; + g_error_free(error); + HandleError(network_state_error); + break; + case GST_MESSAGE_EOS: + VLOG(1) << "GST_MESSAGE_EOS"; +#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) + if (!audio_session_manager_->SetSoundState(ASM_STATE_STOP)) + return; + if (!audio_session_manager_->DeallocateResources()) + return; +#endif + main_loop_->PostTask(FROM_HERE, base::Bind( + &MediaSourcePlayerGstreamer::OnPlaybackComplete, + base::Unretained(this))); + break; + case GST_MESSAGE_ASYNC_DONE: + VLOG(1) << "HandleMessage : GST_MESSAGE_ASYNC_DONE : is_seeking_ = " + << is_seeking_; + if (is_seeking_) { + is_seeking_iframe_ = false; + main_loop_->PostTask(FROM_HERE, base::Bind( + &MediaSourcePlayerGstreamer::UpdateSeekState, + base::Unretained(this), false)); + + // Initiate play for internal seeks. + if (playing_) + main_loop_->PostTask(FROM_HERE, base::Bind( + &MediaSourcePlayerGstreamer::Play, base::Unretained(this))); + + manager()->OnTimeUpdate(GetPlayerId(), GetCurrentTime()); + main_loop_->PostTask(FROM_HERE, base::Bind( + &MediaSourcePlayerGstreamer::OnTimeChanged, base::Unretained(this))); + } + + // FIXME: Do we need to pull caps from PARSER? Can ignore if its of no use. + break; + case GST_MESSAGE_STATE_CHANGED: + if (strcmp(kPipelineName, GST_MESSAGE_SRC_NAME(message))) + break; + main_loop_->PostTask(FROM_HERE, base::Bind( + &MediaSourcePlayerGstreamer::OnUpdateStates, base::Unretained(this))); + break; + case GST_MESSAGE_BUFFERING: + int buffered; + gst_message_parse_buffering(message, &buffered); + + if (audio_queue_ && GST_MESSAGE_SRC(message) == GST_OBJECT(audio_queue_)) + audio_buffered_ = buffered; + if (video_queue_ && GST_MESSAGE_SRC(message) == GST_OBJECT(video_queue_)) + video_buffered_ = buffered; + + if (!is_paused_due_underflow_ && playing_) { + if (audio_buffered_ < 100 || video_buffered_ < 100) { + main_loop_->PostTask(FROM_HERE, base::Bind( + &MediaSourcePlayerGstreamer::HandleBufferingMessage, + base::Unretained(this))); + } + } else if (is_paused_due_underflow_ && playing_) { + if ((!HasAudio() || audio_buffered_ == 100) && + (!HasVideo() || video_buffered_ == 100)) { + main_loop_->PostTask(FROM_HERE, base::Bind( + &MediaSourcePlayerGstreamer::HandleBufferingMessage, + base::Unretained(this))); + } + } + break; + default: + VLOG(1) << "Unhandled GStreamer message type: " + << GST_MESSAGE_TYPE_NAME(message); + break; + } +} + +void MediaSourcePlayerGstreamer::OnUpdateStates() { + DCHECK(main_loop_->BelongsToCurrentThread()); + if (!pipeline_ || IsPlayerDestructing() || error_occured_) + return; + + GstState state; + GstState pending; + GstStateChangeReturn ret = gst_element_get_state( + pipeline_, &state, &pending, 250 * GST_NSECOND); + + VLOG(1) << "MediaSourcePlayerGstreamer::" + << __FUNCTION__ + << " GstStateChangeReturn: " + << gst_element_state_change_return_get_name(ret) + << " state: " + << gst_element_state_get_name(state) + << " pending: " + << gst_element_state_get_name(pending) + << " ID " << GetPlayerId(); + + // FIXME: Handle all state changes + switch (ret) { + case GST_STATE_CHANGE_SUCCESS: + switch (state) { + case GST_STATE_PAUSED: + manager()->OnReadyStateChange( + GetPlayerId(), MediaPlayerEfl::ReadyStateHaveEnoughData); + break; + default: + VLOG(1) << "GStreamer unhandled state " + << gst_element_state_get_name(state); + break; + } + break; + case GST_STATE_CHANGE_FAILURE: + LOG(ERROR) << "Failure: State: " + << gst_element_state_get_name(state) + << " pending: " + << gst_element_state_get_name(pending); + HandleError(MediaPlayerEfl::NetworkStateDecodeError); + break; + case GST_STATE_CHANGE_NO_PREROLL: + + break; + default: + VLOG(1) << "Unhandled return type: " << ret; + break; + } +} + +void MediaSourcePlayerGstreamer::HandleBufferingMessage() { + if (IsPlayerDestructing()) + return; + if (!is_paused_due_underflow_ && + (audio_buffered_ < 100 || video_buffered_ < 100)) { + is_paused_due_underflow_ = true; + Pause(true); + manager()->OnReadyStateChange(GetPlayerId(), + MediaPlayerEfl::ReadyStateHaveCurrentData); + manager()->OnNetworkStateChange(GetPlayerId(), + MediaPlayerEfl::NetworkStateLoading); + } else if (is_paused_due_underflow_ && + (!HasAudio() || audio_buffered_ == 100) && + (!HasVideo() || video_buffered_ == 100)) { + is_paused_due_underflow_ = false; + Play(); + manager()->OnReadyStateChange(GetPlayerId(), + MediaPlayerEfl::ReadyStateHaveEnoughData); + manager()->OnNetworkStateChange(GetPlayerId(), + MediaPlayerEfl::NetworkStateLoaded); + } +} + +void MediaSourcePlayerGstreamer::OnPlaybackComplete() { + // GStreamer pipeline EOS time and media duration doesnt match. + double time = GetCurrentTime() != duration_ ? duration_ : GetCurrentTime(); + is_end_reached_ = true; + is_download_finished_ = false; + StopCurrentTimeUpdateTimer(); + manager()->OnTimeUpdate(GetPlayerId(), time); + manager()->OnTimeChanged(GetPlayerId()); + +#if defined(OS_TIZEN_MOBILE) && (defined(TIZEN_V_2_3) || defined(TIZEN_V_2_4)) + if (device_power_release_lock(POWER_LOCK_DISPLAY) != DEVICE_ERROR_NONE) + LOG(ERROR) << "|device_power_release_lock| request failed"; +#endif + +} + +void MediaSourcePlayerGstreamer::UpdateSeekState(bool state) { + manager()->OnSeekStateChange(GetPlayerId(), state); + is_seeking_ = state; +} + +void MediaSourcePlayerGstreamer::OnTimeChanged() { + VLOG(1) << "OnTimeChanged" << "Player ID : " << GetPlayerId(); + DCHECK(main_loop_->BelongsToCurrentThread()); + manager()->OnTimeChanged(GetPlayerId()); +} + +void MediaSourcePlayerGstreamer::HandleError( + media::MediaPlayerEfl::NetworkState state) { + error_occured_ = true; + manager()->OnNetworkStateChange(GetPlayerId(), state); + +#if defined(OS_TIZEN_MOBILE) && (defined(TIZEN_V_2_3) || defined(TIZEN_V_2_4)) + if (device_power_release_lock(POWER_LOCK_DISPLAY) != DEVICE_ERROR_NONE) + LOG(ERROR) << "|device_power_release_lock| request failed"; +#endif + +} + +void MediaSourcePlayerGstreamer::ReleaseAudioElements() { + if (audio_appsrc_) { + gst_object_unref(audio_appsrc_); + audio_appsrc_ = NULL; + } + + if (audio_queue_) { + gst_object_unref(audio_queue_); + audio_queue_ = NULL; + } + + if (audio_parse_) { + gst_object_unref(audio_parse_); + audio_parse_ = NULL; + } + + if (audio_decoder_) { + gst_object_unref(audio_decoder_); + audio_decoder_ = NULL; + } + + if (audio_convert_) { + gst_object_unref(audio_convert_); + audio_convert_ = NULL; + } + + if (audio_resampler_) { + gst_object_unref(audio_resampler_); + audio_resampler_ = NULL; + } + + if (audio_volume_) { + gst_object_unref(audio_volume_); + audio_volume_ = NULL; + } + + if (audio_sink_) { + gst_object_unref(audio_sink_); + audio_sink_ = NULL; + } +} + +void MediaSourcePlayerGstreamer::ReleaseVideoElements() { + if(video_appsrc_) { + gst_object_unref(video_appsrc_); + video_appsrc_ = NULL; + } + + if(video_parse_) { + gst_object_unref(video_parse_); + video_parse_ = NULL; + } + + if(video_queue_) { + gst_object_unref(video_queue_); + video_queue_ = NULL; + } + + if(video_decoder_) { + gst_object_unref(video_decoder_); + video_decoder_ = NULL; + } + + if(video_sink_) { + gst_object_unref(video_sink_); + video_sink_ = NULL; + } +} + +} // namespace media diff --git a/tizen_src/chromium_impl/media/base/efl/media_source_player_gstreamer.h b/tizen_src/chromium_impl/media/base/efl/media_source_player_gstreamer.h new file mode 100644 index 000000000000..af502b7e3a06 --- /dev/null +++ b/tizen_src/chromium_impl/media/base/efl/media_source_player_gstreamer.h @@ -0,0 +1,254 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_BASE_TIZEN_MEDIA_SOURCE_PLAYER_GSTREAMER_H_ +#define MEDIA_BASE_TIZEN_MEDIA_SOURCE_PLAYER_GSTREAMER_H_ + +#include + +#include +#include "ecore_x_wrapper.h" +#include + +#include "base/cancelable_callback.h" +#include "base/memory/scoped_ptr.h" +#include "base/threading/thread.h" +#include "base/time/default_tick_clock.h" +#include "base/timer/timer.h" +#include "media/base/efl/demuxer_efl.h" +#include "media/base/efl/media_player_efl.h" +#include "media/base/decoder_buffer.h" + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +#include "ui/gl/efl_pixmap.h" +#endif + +#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) +#include "media/audio/tizen/audio_session_manager.h" +#endif + +namespace { +struct AudioCodecGstElementsMapping { + media::AudioCodec codec; + const char **elements; +}; + +struct VideoCodecGstElementsMapping { + media::VideoCodec codec; + const char **elements; +}; +} + +namespace media { + +// This class handles media source extensions for Gstreamer port. +class MEDIA_EXPORT MediaSourcePlayerGstreamer : public MediaPlayerEfl, + public DemuxerEflClient { + public: + + // Constructs a player with the given ID and demuxer. |manager| must outlive + // the lifetime of this object. + MediaSourcePlayerGstreamer( + int player_id, + scoped_ptr demuxer, + MediaPlayerManager* manager); + + virtual ~MediaSourcePlayerGstreamer(); + + // MediaPlayerEfl implementation. + virtual void Play() override; + virtual void Pause(bool is_media_related_action) override; + virtual void SetRate(double rate) override; + virtual void Seek(const double time) override; + virtual void SetVolume(double volume) override; + virtual double GetCurrentTime() override; + virtual void Destroy() override; + + // DemuxerEflClient implementation. + virtual void OnDemuxerConfigsAvailable( + const DemuxerConfigs& params) override; + virtual void OnDemuxerDataAvailable( + base::SharedMemoryHandle foreign_memory_handle, + const media::DemuxedBufferMetaData& meta_data) override; + virtual void OnBufferMetaDataAvailable( + const media::DemuxedBufferMetaData& meta_data) override; + virtual void OnDemuxerSeekDone( + const base::TimeDelta& actual_browser_seek_time) override; + virtual void OnDemuxerDurationChanged(base::TimeDelta duration) override; + + // GStreamer Message handler + void HandleMessage(GstMessage* message); + + // AppSink related + void GetFrameDetails(); +#if GST_VERSION_MAJOR == 1 + GstSample* PullSample(); + void OnNewFrameAvailable(GstSample* sample); +#else + GstBuffer* PullSample(); + void OnNewFrameAvailable(const GstBuffer* buffer); +#endif + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + void PlatformSurfaceUpdated(); + void OnVideoConfigsChanged(); + int GetSurfaceID() const; +#endif + + void OnReadDemuxedData(media::DemuxerStream::Type type); + void OnStopDemuxedData(media::DemuxerStream::Type type); + + void UpdateVideoSeekOffset(guint64 video_seek_offset) { + video_seek_offset_ = video_seek_offset; + } + void UpdateAudioSeekOffset(guint64 audio_seek_offset) { + audio_seek_offset_ = audio_seek_offset; + } + + protected: + virtual void Release() override; + + private: + void PrepareForVideoFrame(); + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + void PrepareForVideoSink(); + void VideoConfigsChanged(); + void CreatePixmap(); + void SetPixmap(); + bool IsXWindowHadleSet() { return is_xwindow_handle_set_;} + void XWindowIdPrepared(GstMessage*); + void UnregisterDamageHandler(); +#endif + + void ReadDemuxedData(media::DemuxerStream::Type type); + void SaveDecoderBuffer( + base::SharedMemoryHandle foreign_memory_handle, + const media::DemuxedBufferMetaData& meta_data); + void ReadFromQueueIfAny(DemuxerStream::Type type); + + bool HasAudio(); + bool HasVideo(); + + // Note: Must be invoked only if elements are not added into the pipeline. + void ReleaseAudioElements(); + void ReleaseVideoElements(); + + void SeekInternal(const GstClockTime time); + + // For internal seeks. + void RequestPlayerSeek(double seekTime); + + // |current_time_update_timer_| related + void OnCurrentTimeUpdateTimerFired(); + void StartCurrentTimeUpdateTimer(); + void StopCurrentTimeUpdateTimer(); + void OnGetFrameDetails(); + + void OnUpdateStates(); + void HandleBufferingMessage(); + void OnPlaybackComplete(); + void UpdateSeekState(bool state); + void OnTimeChanged(); + + // Error handling API + void HandleError(media::MediaPlayerEfl::NetworkState state); + + scoped_ptr demuxer_; + + const scoped_refptr main_loop_; + +#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) + scoped_refptr audio_session_manager_; +#endif + + // Stats about the media. + bool playing_; + + // Weak pointer passed to media decoder jobs for callbacks. + base::WeakPtrFactory weak_this_; + + // To support Vedio Sink (pixmap). +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + int pixmap_id_; + scoped_refptr efl_pixmap_; + Ecore_X_Damage m_damage; + Ecore_Event_Handler* m_damageHandler; + typedef std::map > EflPixmapMap; + EflPixmapMap efl_pixmaps_map_; +#endif + + // Will allow to listen to |prepare-xid| message only once. + bool is_xwindow_handle_set_; + + // Whenever resolution changes, to change the pixmap + // if Video Playback is backed by |pixmap|. + bool is_backed_by_pixmap; + + GstElement* pipeline_; + GstElement* video_appsrc_; + GstElement* video_parse_; + GstElement* video_decoder_; + GstElement* video_sink_; + GstElement* audio_appsrc_; + GstElement* audio_decoder_; + GstElement* audio_sink_; + GstElement* video_queue_; + GstElement* audio_queue_; + GstElement* audio_parse_; + GstElement* audio_convert_; + GstElement* audio_resampler_; + GstElement* audio_volume_; + GstPad* video_sink_pad_; + bool should_feed_audio_; + bool should_feed_video_; + + int gst_width_; + int gst_height_; + guint32 video_format_; + int media_type; + int bufsize_sn12_; + double play_rate_; + double duration_; + bool is_paused_due_underflow_; + + base::SharedMemory shared_memory; + uint32 shared_memory_size; + base::SharedMemoryHandle foreign_memory_handle; + + int buffered_; + bool is_paused_; + bool is_seeking_; + bool is_demuxer_seeking_; + int audio_buffered_; + int video_buffered_; + + bool is_gst_pipeline_constructed_; + std::deque > audio_buffer_queue_; + std::deque > video_buffer_queue_; + + bool is_download_finished_; + bool is_end_reached_; + bool error_occured_; + + base::RepeatingTimer current_time_update_timer_; + int raw_video_frame_size_; + guint64 video_seek_offset_; + guint64 audio_seek_offset_; + + // When seeked to |x| seconds, |ChunkDemuxer| will send data from + // |x - delta_x| where |x-delta_x| is location of I-Frame. And gstreamer + // decoder is supposed to play media from seek time i.e. |x| seconds. + // But in the gstreamer pipeline created here it starts playing from I-Frame + // i.e. |x-delta_x| but gst-pipeline time starts running from |x|. Hence + // jerky playback is observed for some time during seek. To avoid this, now + // gst-pipeline is also seeked to nearest I-Frame i.e. |x-delta_x|. + bool is_seeking_iframe_; + + DISALLOW_COPY_AND_ASSIGN(MediaSourcePlayerGstreamer); +}; + +} // namespace media + +#endif // MEDIA_BASE_TIZEN_MEDIA_SOURCE_PLAYER_GSTREAMER_H_ diff --git a/tizen_src/chromium_impl/media/base/efl/webaudio_media_codec_info_efl.h b/tizen_src/chromium_impl/media/base/efl/webaudio_media_codec_info_efl.h new file mode 100644 index 000000000000..b44c056b2344 --- /dev/null +++ b/tizen_src/chromium_impl/media/base/efl/webaudio_media_codec_info_efl.h @@ -0,0 +1,20 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_BASE_TIZEN_WEBAUDIO_MEDIA_CODEC_INFO_EFL_H_ +#define MEDIA_BASE_TIZEN_WEBAUDIO_MEDIA_CODEC_INFO_EFL_H_ + +namespace media { + +// This structure holds the information about the audio file +// determined by MediaCodec that is needed by the audio decoder to +// create the necessary destination bus. +struct WebAudioMediaCodecInfoEfl { + unsigned long channel_count; + unsigned long sample_rate; + unsigned long number_of_frames; +}; + +} // namespace media +#endif // MEDIA_BASE_TIZEN_WEBAUDIO_MEDIA_CODEC_INFO_EFL_H_ diff --git a/tizen_src/chromium_impl/media/base/efl/webmediaplayer_efl.cc b/tizen_src/chromium_impl/media/base/efl/webmediaplayer_efl.cc new file mode 100644 index 000000000000..22769dda36e3 --- /dev/null +++ b/tizen_src/chromium_impl/media/base/efl/webmediaplayer_efl.cc @@ -0,0 +1,710 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/base/efl/webmediaplayer_efl.h" + +#include + +#include "cc/blink/web_layer_impl.h" +#include "cc/layers/video_layer.h" +#include "content/common/wrt/wrt_url_parse.h" +#include "content/renderer/media/render_media_log.h" +#include "content/renderer/media/renderer_gpu_video_accelerator_factories.h" +#include "content/renderer/render_frame_impl.h" +#include "content/renderer/render_thread_impl.h" +#include "media/base/efl/media_player_efl.h" +#include "media/base/bind_to_current_loop.h" +#include "media/base/video_frame.h" +#include "media/blink/webmediaplayer_util.h" +#include "third_party/libyuv/include/libyuv/planar_functions.h" +#include "third_party/WebKit/public/platform/WebMediaPlayerClient.h" + +#define BIND_TO_RENDER_LOOP(function) \ + (DCHECK(main_loop_->BelongsToCurrentThread()), \ + media::BindToCurrentLoop(base::Bind(function, AsWeakPtr()))) + +namespace media { + +// fourcc for gst-video-format +const uint32 GST_VIDEO_SN12 = GST_MAKE_FOURCC('S','N','1','2'); +const uint32 GST_VIDEO_I420 = GST_MAKE_FOURCC('I','4','2','0'); +const uint32 GST_VIDEO_NV12 = GST_MAKE_FOURCC('N','V','1','2'); + +// tile size for SN12 +const uint SN12_TILE_WIDTH = 64; +const uint SN12_TILE_HEIGHT = 32; +const uint SN12_TILE_SIZE = SN12_TILE_WIDTH * SN12_TILE_HEIGHT; + +// Removes query string from URI +GURL GetCleanURL(std::string url) { + // FIXME: Need to consider "app://" scheme. + if (!url.compare(0, 7, "file://")) { + int position = url.find("?"); + if(position != -1) + url.erase(url.begin() + position, url.end()); + } + GURL url_(url); + return url_; +} + +WebMediaPlayerEfl::WebMediaPlayerEfl( + content::RendererMediaPlayerManagerEfl* manager, + blink::WebLocalFrame* frame, + blink::WebMediaPlayerClient* client, + base::WeakPtr delegate, + const WebMediaPlayerParams& params, + content::WrtUrlParseBase* wrt_url_parse) + : frame_(frame), + network_state_(blink::WebMediaPlayer::NetworkStateEmpty), + ready_state_(blink::WebMediaPlayer::ReadyStateHaveNothing), + main_loop_(base::MessageLoopProxy::current()), + media_task_runner_( + content::RenderThreadImpl::current()->GetMediaThreadTaskRunner()), + manager_(manager), + client_(client), + media_log_(new content::RenderMediaLog()), + delegate_(delegate), + compositor_task_runner_( + content::RenderThreadImpl::current()->compositor_message_loop_proxy()), + compositor_(new media::VideoFrameCompositor( + BIND_TO_RENDER_LOOP(&WebMediaPlayerEfl::OnNaturalSizeChanged), + BIND_TO_RENDER_LOOP(&WebMediaPlayerEfl::OnOpacityChanged))), + weak_factory_(this), + gst_video_format_(0), + audio_(false), + video_(false), + current_time_(0), + duration_(0), + is_paused_(true), + is_seeking_(false), + seek_time_(0), + pending_seek_(0), + pending_seek_time_(0), + opaque_(false), + natural_size_(0, 0), + did_loading_progress_(false), + volume_(0), + gpu_factories_(content::RenderThreadImpl::current()->GetGpuFactories()), + encrypted_media_support_( + params.CreateEncryptedMediaPlayerSupport(client)), + wrt_url_parse_(wrt_url_parse) { + DCHECK(manager_); + DCHECK(encrypted_media_support_); + VLOG(1) << "WebMediaPlayerEfl::" << __FUNCTION__; + FrameAvailable_ = false; + // We want to be notified of |main_loop_| destruction. + base::MessageLoop::current()->AddDestructionObserver(this); + + player_id_ = manager_->RegisterMediaPlayer(this); + + // Threaded compositing isn't enabled universally yet. + if (!compositor_task_runner_.get()) + compositor_task_runner_ = base::MessageLoopProxy::current(); + + media_log_->AddEvent( + media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_CREATED)); +} + +WebMediaPlayerEfl::~WebMediaPlayerEfl() { + VLOG(1) << "WebMediaPlayerEfl::" << __FUNCTION__; + if (manager_) { + manager_->DestroyPlayer(player_id_); + manager_->UnregisterMediaPlayer(player_id_); + } + + SetVideoFrameProviderClient(NULL); + client_->setWebLayer(NULL); + if (delegate_.get()) + delegate_->PlayerGone(this); + if (base::MessageLoop::current()) + base::MessageLoop::current()->RemoveDestructionObserver(this); + compositor_task_runner_->DeleteSoon(FROM_HERE, compositor_); + if (media_source_delegate_) { + // Part of |media_source_delegate_| needs to be stopped + // on the media thread. + // Wait until |media_source_delegate_| is fully stopped + // before tearing down other objects. + base::WaitableEvent waiter(false, false); + media_source_delegate_->Stop( + base::Bind(&base::WaitableEvent::Signal, base::Unretained(&waiter))); + waiter.Wait(); + } +} + +void WebMediaPlayerEfl::load(LoadType load_type, + const blink::WebURL& url, + CORSMode cors_mode) { + VLOG(1) << "WebMediaPlayerEfl::" << __FUNCTION__ << " load type - " + << load_type; + int demuxer_client_id = 0; + if (load_type == LoadTypeMediaSource) { + // FIXME: EFL GST-package on desktop cannot handle AAC decoding. + // Disabling MSE for desktop. +#ifdef OS_TIZEN + player_type_ = MEDIA_PLAYER_TYPE_MEDIA_SOURCE; + content::RendererDemuxerEfl* demuxer = + content::RenderThreadImpl::current()->renderer_demuxer(); + demuxer_client_id = demuxer->GetNextDemuxerClientID(); + media_source_delegate_.reset(new content::MediaSourceDelegateEfl( + demuxer, demuxer_client_id, media_task_runner_, media_log_.get())); + SetDecryptorReadyCB set_decryptor_ready_cb = + encrypted_media_support_->CreateSetDecryptorReadyCB(); + Demuxer::NeedKeyCB need_key_cb = + encrypted_media_support_->CreateNeedKeyCB(); + media_source_delegate_->InitializeMediaSource( + base::Bind(&WebMediaPlayerEfl::OnMediaSourceOpened, + weak_factory_.GetWeakPtr()), + need_key_cb, + set_decryptor_ready_cb, + base::Bind(&WebMediaPlayerEfl::SetNetworkState, + weak_factory_.GetWeakPtr()), + base::Bind(&WebMediaPlayerEfl::OnDurationChange, + weak_factory_.GetWeakPtr())); +#else + // Posting Error Message to HTMLMediaElement. + SetNetworkState(WebMediaPlayer::NetworkStateDecodeError); +#endif + } else if (load_type == LoadTypeURL) { + player_type_ = MEDIA_PLAYER_TYPE_URL; + } else { + LOG(ERROR) << "Unsupported load type " << load_type; + return; + } + + blink::WebURL real_url; + if (wrt_url_parse_) + real_url = wrt_url_parse_->parseUrl(url); + else + real_url = url; + + // FIXME: Check URL, Volume for MS. + manager_->Initialize(player_id_, + player_type_, + GetCleanURL(real_url.string().utf8()), + volume_, + demuxer_client_id); +} + +blink::WebMediaPlayer::MediaKeyException +WebMediaPlayerEfl::generateKeyRequest(const blink::WebString& key_system, + const unsigned char* init_data, + unsigned init_data_length) { + DCHECK(main_loop_->BelongsToCurrentThread()); + + return encrypted_media_support_->GenerateKeyRequest( + frame_, key_system, init_data, init_data_length); +} + +blink::WebMediaPlayer::MediaKeyException WebMediaPlayerEfl::addKey( + const blink::WebString& key_system, + const unsigned char* key, + unsigned key_length, + const unsigned char* init_data, + unsigned init_data_length, + const blink::WebString& session_id) { + DCHECK(main_loop_->BelongsToCurrentThread()); + + return encrypted_media_support_->AddKey( + key_system, key, key_length, init_data, init_data_length, session_id); +} + +blink::WebMediaPlayer::MediaKeyException WebMediaPlayerEfl::cancelKeyRequest( + const blink::WebString& key_system, + const blink::WebString& session_id) { + DCHECK(main_loop_->BelongsToCurrentThread()); + + return encrypted_media_support_->CancelKeyRequest(key_system, session_id); +} + +void WebMediaPlayerEfl::setContentDecryptionModule( + blink::WebContentDecryptionModule* cdm) { + DCHECK(main_loop_->BelongsToCurrentThread()); + + encrypted_media_support_->SetContentDecryptionModule(cdm); +} + +void WebMediaPlayerEfl::setContentDecryptionModule( + blink::WebContentDecryptionModule* cdm, + blink::WebContentDecryptionModuleResult result) { + DCHECK(main_loop_->BelongsToCurrentThread()); + + encrypted_media_support_->SetContentDecryptionModule(cdm, result); +} + +void WebMediaPlayerEfl::OnMediaSourceOpened( + blink::WebMediaSource* web_media_source) { + client_->mediaSourceOpened(web_media_source); +} + +void WebMediaPlayerEfl::play() { + manager_->Play(player_id_); + // Has to be updated from |MediaPlayerBridgeGstreamer| but IPC causes delay. + // There are cases were play - pause are fired successively and would fail. + is_paused_ = false; +} + +void WebMediaPlayerEfl::pause() { + manager_->Pause(player_id_, true); + // Has to be updated from |MediaPlayerBridgeGstreamer| but IPC causes delay. + // There are cases were play - pause are fired successively and would fail. + is_paused_ = true; +} + +void WebMediaPlayerEfl::RequestPause() { + pause(); + client_->playbackStateChanged(); +} + +bool WebMediaPlayerEfl::supportsSave() const { + return false; +} + +void WebMediaPlayerEfl::seek(double seconds) { + VLOG(1) << "WebMediaPlayerEfl::" << __FUNCTION__ << " : " << seconds + << " ID " << player_id_; + DCHECK(main_loop_->BelongsToCurrentThread()); + + if (is_seeking_) { + if (seconds == seek_time_) { + if (media_source_delegate_) { + if (!pending_seek_) { + // If using media source demuxer, only suppress redundant seeks if + // there is no pending seek. This enforces that any pending seek that + // results in a demuxer seek is preceded by matching + // CancelPendingSeek() and StartSeek() calls. + return; + } + } else { + // Suppress all redundant seeks if unrestricted by media source + // demuxer API. + pending_seek_ = false; + return; + } + } + + pending_seek_ = true; + pending_seek_time_ = seconds; + if (media_source_delegate_) + media_source_delegate_->CancelPendingSeek( + media::ConvertSecondsToTimestamp(pending_seek_time_)); + // Later, OnSeekComplete will trigger the pending seek. + return; + } + + is_seeking_ = true; + seek_time_ = seconds; + + // Once Chunk demuxer seeks GST seek will be intiated. + if (media_source_delegate_) + media_source_delegate_->StartWaitingForSeek( + media::ConvertSecondsToTimestamp(seek_time_)); + manager_->Seek(player_id_, seek_time_); + + // Draw empty frame during seek. + if (video_) { + gfx::Size size(gst_width_, gst_height_); + scoped_refptr video_frame = VideoFrame::CreateBlackFrame(size); + FrameReady(video_frame); + } +} + +void WebMediaPlayerEfl::setRate(double rate) { + manager_->SetRate(player_id_, rate); +} + +void WebMediaPlayerEfl::setVolume(double volume) { + volume_ = volume; + manager_->SetVolume(player_id_, volume); +} + +blink::WebTimeRanges WebMediaPlayerEfl::buffered() const{ + return buffered_; +} + +blink::WebTimeRanges WebMediaPlayerEfl::seekable() const { + const double seekable_end = duration(); + if (std::isinf(seekable_end)) + return blink::WebTimeRanges(); + + blink::WebTimeRange seekable_range(0.0, seekable_end); + return blink::WebTimeRanges(&seekable_range, 1); +} + +void WebMediaPlayerEfl::paint(blink::WebCanvas* canvas, + const blink::WebRect& rect, + unsigned char alpha, + SkXfermode::Mode mode) { + scoped_refptr video_frame = + GetCurrentFrameFromCompositor(); + + gfx::Rect gfx_rect(rect); + skcanvas_video_renderer_.Paint( + video_frame.get(), canvas, gfx_rect, alpha, + SkXfermode::kSrcOver_Mode, media::VIDEO_ROTATION_0); +} + +bool WebMediaPlayerEfl::hasVideo() const { + return video_; +} + +bool WebMediaPlayerEfl::hasAudio() const { + return audio_; +} + +blink::WebSize WebMediaPlayerEfl::naturalSize() const { + return blink::WebSize(natural_size_); +} + +bool WebMediaPlayerEfl::paused() const { + return is_paused_; +} + +bool WebMediaPlayerEfl::seeking() const { + return is_seeking_; +} + +double WebMediaPlayerEfl::duration() const { + return duration_; +} + +double WebMediaPlayerEfl::currentTime() const { + if (seeking()) + return pending_seek_ ? pending_seek_time_ : seek_time_; + return current_time_; +} + +blink::WebMediaPlayer::NetworkState WebMediaPlayerEfl::networkState() const { + return network_state_; +} + +blink::WebMediaPlayer::ReadyState WebMediaPlayerEfl::readyState() const { + return ready_state_; +} + +bool WebMediaPlayerEfl::didLoadingProgress() { + if (did_loading_progress_) { + did_loading_progress_ = false; + return true; + } + return false; +} + +bool WebMediaPlayerEfl::hasSingleSecurityOrigin() const { + return true; +} + +bool WebMediaPlayerEfl::didPassCORSAccessCheck() const { + return false; +} + +double WebMediaPlayerEfl::mediaTimeForTimeValue(double timeValue) const { + return media::ConvertSecondsToTimestamp(timeValue).InSecondsF(); +} + +unsigned WebMediaPlayerEfl::decodedFrameCount() const { + return 0; +}; + +unsigned WebMediaPlayerEfl::droppedFrameCount() const { + return 0; +}; + +unsigned WebMediaPlayerEfl::audioDecodedByteCount() const { + return 0; +}; + +unsigned WebMediaPlayerEfl::videoDecodedByteCount() const { + return 0; +}; + +void WebMediaPlayerEfl::SetVideoFrameProviderClient( + cc::VideoFrameProvider::Client* client) { + // This is called from both the main renderer thread and the compositor + // thread (when the main thread is blocked). + compositor_->SetVideoFrameProviderClient(client); +} + +scoped_refptrWebMediaPlayerEfl::GetCurrentFrame() { + scoped_refptr current_frame = + GetCurrentFrameFromCompositor(); + return current_frame; +} + +void WebMediaPlayerEfl::SetReadyState(WebMediaPlayer::ReadyState state) { + ready_state_ = state; + client_->readyStateChanged(); +} + +void WebMediaPlayerEfl::SetNetworkState(WebMediaPlayer::NetworkState state) { + network_state_ = state; + client_->networkStateChanged(); +} + +void WebMediaPlayerEfl::OnNewFrameAvailable(base::SharedMemoryHandle Handle, + uint32 yuv_size, + base::TimeDelta timestamp) { + base::SharedMemory shared_memory(Handle, false); + shared_memory.Map(yuv_size); + uint8* const yuv_buffer = static_cast(shared_memory.memory()); + + gfx::Size size(gst_width_, gst_height_); + scoped_refptr video_frame = + VideoFrame::CreateFrame( + VideoFrame::YV12, size, gfx::Rect(size), size, timestamp); + + // decoded format is SN12 on Tizen device + // video format converted from SN12 to YV12 + uint8* gst_buf = yuv_buffer; + switch(gst_video_format_) { + case GST_VIDEO_I420: { + const uint c_frm_size = yuv_size / 6; + const uint y_frm_size = c_frm_size << 2; // * 4; + // U Plane buffer. + uint8* gst_buf_u = gst_buf + y_frm_size; + // V Plane buffer. + uint8* gst_buf_v = gst_buf_u + c_frm_size; + + + // Get the videoframe stride size. + // Calculate the gstreamer buffer stride size. + const uint uv_rows = video_frame.get()->rows(VideoFrame::kUPlane); + const uint gst_stride = c_frm_size / uv_rows; + + libyuv::I420Copy(gst_buf, 2 * gst_stride, + gst_buf_u, gst_stride, + gst_buf_v, gst_stride, + video_frame.get()->data(VideoFrame::kYPlane), + video_frame.get()->stride(VideoFrame::kYPlane), + video_frame.get()->data(VideoFrame::kUPlane), + video_frame.get()->stride(VideoFrame::kUPlane), + video_frame.get()->data(VideoFrame::kVPlane), + video_frame.get()->stride(VideoFrame::kVPlane), + gst_width_, gst_height_); + break; + } + case GST_VIDEO_SN12: { + //const uint tile_w = (gst_width_ - 1) / SN12_TILE_WIDTH + 1; + //const uint tile_w_align = (tile_w + 1) & ~1; + //const uint tile_h_luma = (gst_height_ - 1) / SN12_TILE_HEIGHT + 1; + const uint tile_w_align = ((gst_width_ - 1) / SN12_TILE_WIDTH + 2) & ~1; + const uint tile_luma_stride = tile_w_align * SN12_TILE_WIDTH; + uint luma_size = SN12_TILE_SIZE * tile_w_align + * ((gst_height_-1)/SN12_TILE_HEIGHT + 1); + + uint8* y_frm = video_frame.get()->data(VideoFrame::kYPlane); + const uint y_stride = video_frame.get()->stride(VideoFrame::kYPlane); + + // actually copy and convert luma buffer + for(int i=0; idata(VideoFrame::kUPlane); + uint8* v_frm = video_frame.get()->data(VideoFrame::kVPlane); + const uint uv_stride = video_frame.get()->stride(VideoFrame::kUPlane); + const uint uv_rows = video_frame.get()->rows(VideoFrame::kUPlane); + + // actually copy and convert chroma buffer + for(uint row=0; rowdata(VideoFrame::kYPlane), + gst_buf, y_frm_size); + + gst_buf += y_frm_size; + uint8* gst_buf2 = gst_buf + 1; + uint8* u_plane = video_frame.get()->data(VideoFrame::kUPlane); + uint8* v_plane = video_frame.get()->data(VideoFrame::kVPlane); + + for(uint i = 0; i < c_frm_size; i++){ + // kUPlane + u_plane[i] = gst_buf[i * 2]; + // kVPlane + v_plane[i] = gst_buf2[i * 2]; + } + break; + } + default: { + LOG(ERROR) << "WebMediaPlayerEfl::" << __FUNCTION__ + << " not supported video format"; + break; + } + } + + shared_memory.Close(); + FrameReady(video_frame); +} + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +// FIXME: Graphics team need to merge painting of Video-Frame on to 2d-canvas +// from m34. +void WebMediaPlayerEfl::OnPlatformSurfaceUpdated( + int pixmap_id, + base::TimeDelta timestamp) { + gfx::Size size(gst_width_, gst_height_); + scoped_refptr video_frame = VideoFrame::WrapNativePixmap( + VideoFrame::NATIVE_PIXMAP, size, gfx::Rect(size), size, + timestamp, pixmap_id); + FrameReady(video_frame); +} +#endif + +void WebMediaPlayerEfl::FrameReady( + const scoped_refptr& frame) { + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&media::VideoFrameCompositor::UpdateCurrentFrame, + base::Unretained(compositor_), + frame)); +} +void WebMediaPlayerEfl::OnMediaDataChange(int format, int height, int width, int media) { + gst_video_format_ = static_cast(format); + gst_height_ = height; + gst_width_ = width; + audio_ = media & media::MEDIA_AUDIO_MASK ? true : false; + video_ = media & media::MEDIA_VIDEO_MASK ? true : false; + natural_size_ = gfx::Size(width, height); + SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); + if (hasVideo() && !video_weblayer_.get()) { + scoped_refptr layer = + cc::VideoLayer::Create(compositor_, media::VIDEO_ROTATION_0); + video_weblayer_.reset(new cc_blink::WebLayerImpl(layer)); + video_weblayer_->setOpaque(opaque_); + client_->setWebLayer(video_weblayer_.get()); + } +} + +void WebMediaPlayerEfl::OnTimeChanged() { + is_seeking_ = false; + + // Handling pending seek for ME. For MSE |CancelPendingSeek| + // will handle the pending seeks. + if (!media_source_delegate_ && pending_seek_) { + pending_seek_ = false; + seek(pending_seek_time_); + return; + } + client_->timeChanged(); +} + +void WebMediaPlayerEfl::OnDurationChange(double duration) { + duration_ = duration; + client_->durationChanged(); +} + +void WebMediaPlayerEfl::OnNaturalSizeChanged(gfx::Size size) { + DCHECK(main_loop_->BelongsToCurrentThread()); + DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing); + TRACE_EVENT0("media", "WebMediaPlayerEfl::OnNaturalSizeChanged"); + media_log_->AddEvent( + media_log_->CreateVideoSizeSetEvent(size.width(), size.height())); + natural_size_ = size; + + client_->sizeChanged(); +} + +void WebMediaPlayerEfl::OnOpacityChanged(bool opaque) { + DCHECK(main_loop_->BelongsToCurrentThread()); + DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing); + + opaque_ = opaque; + if (video_weblayer_) + video_weblayer_->setOpaque(opaque_); +} + +static void GetCurrentFrameAndSignal( + media::VideoFrameCompositor* compositor, + scoped_refptr* video_frame_out, + base::WaitableEvent* event) { + TRACE_EVENT0("media", "GetCurrentFrameAndSignal"); + *video_frame_out = compositor->GetCurrentFrame(); + event->Signal(); +} + +scoped_refptr + WebMediaPlayerEfl::GetCurrentFrameFromCompositor() { + TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor"); + + if (compositor_task_runner_->BelongsToCurrentThread()) + return compositor_->GetCurrentFrame(); + + // Use a posted task and waitable event instead of a lock otherwise + // WebGL/Canvas can see different content than what the compositor is seeing. + scoped_refptr video_frame; + base::WaitableEvent event(false, false); + compositor_task_runner_->PostTask(FROM_HERE, + base::Bind(&GetCurrentFrameAndSignal, + base::Unretained(compositor_), + &video_frame, + &event)); + event.Wait(); + return video_frame; +} + +void WebMediaPlayerEfl::OnTimeUpdate(double current_time) { + current_time_ = current_time; +} + +void WebMediaPlayerEfl::OnBufferUpdate( + std::vector buffer_range) { + media::Ranges time_ranges; + std::vector::iterator tr_it; + for ( tr_it = buffer_range.begin(); tr_it != buffer_range.end(); ++tr_it) { + time_ranges.Add( + base::TimeDelta::FromMicroseconds((*tr_it).start), + base::TimeDelta::FromMicroseconds((*tr_it).end)); + } + blink::WebTimeRanges web_ranges(ConvertToWebTimeRanges(time_ranges)); + buffered_.swap(web_ranges); + did_loading_progress_ = true; +} + +void WebMediaPlayerEfl::OnPauseStateChange(bool state) { + VLOG(1) << "WebMediaPlayerEfl::" << __FUNCTION__ << " state:" << state; + is_paused_ = state; + if (delegate_.get()) { + if(is_paused_) + delegate_->DidPause(this); + else + delegate_->DidPlay(this); + } +} + +void WebMediaPlayerEfl::OnSeekStateChange(bool state) { + VLOG(1) << "WebMediaPlayerEfl::" << __FUNCTION__ << " state:" << state + << " ID " << player_id_; + is_seeking_ = state; + // Draw empty frame during seek. + if (video_ && is_seeking_) { + gfx::Size size(gst_width_, gst_height_); + scoped_refptr video_frame = VideoFrame::CreateBlackFrame(size); + FrameReady(video_frame); + } +} + +void WebMediaPlayerEfl::OnRequestSeek(double seek_time) { + client_->requestSeek(seek_time); +} + +} // namespace media diff --git a/tizen_src/chromium_impl/media/base/efl/webmediaplayer_efl.h b/tizen_src/chromium_impl/media/base/efl/webmediaplayer_efl.h new file mode 100644 index 000000000000..d524d8330bf3 --- /dev/null +++ b/tizen_src/chromium_impl/media/base/efl/webmediaplayer_efl.h @@ -0,0 +1,247 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_RENDERER_MEDIA_TIZEN_WEBMEDIAPLAYER_EFL_H_ +#define CONTENT_RENDERER_MEDIA_TIZEN_WEBMEDIAPLAYER_EFL_H_ + +#include "base/message_loop/message_loop.h" +#include "cc/layers/video_frame_provider_client_impl.h" +#include "content/renderer/media/efl/media_source_delegate_efl.h" +#include "content/renderer/media/efl/renderer_media_player_manager_efl.h" +#include "media/blink/video_frame_compositor.h" +#include "media/blink/webmediaplayer_params.h" +#include "media/filters/skcanvas_video_renderer.h" + +namespace blink { +class WebLocalFrame; +} + +namespace cc_blink { +class WebLayerImpl; +} + +namespace content { +class RendererMediaPlayerManagerEfl; +class WrtUrlParseBase; +} + +namespace media { + +class GpuVideoAcceleratorFactories; +class WebMediaPlayerDelegate; + +// This class implements blink::WebMediaPlayer by keeping the tizen +// media player in the browser process. It listens to all the status changes +// sent from the browser process and sends playback controls to the media +// player. +class WebMediaPlayerEfl + : public blink::WebMediaPlayer, + public cc::VideoFrameProvider, + public base::MessageLoop::DestructionObserver, + public base::SupportsWeakPtr { + public: + // Construct a WebMediaPlayerEfl object. This class communicates + // with the WebMediaPlayerEfl object in the browser process through + // |proxy|. + WebMediaPlayerEfl( + content::RendererMediaPlayerManagerEfl* manager, + blink::WebLocalFrame* frame, + blink::WebMediaPlayerClient* client, + base::WeakPtr delegate, + const WebMediaPlayerParams& params, + content::WrtUrlParseBase* wrt_url_parse); + virtual ~WebMediaPlayerEfl(); + + // blink::WebMediaPlayer implementation. + void load(LoadType load_type, + const blink::WebURL& url, + CORSMode cors_mode) override; + + // Playback controls. + void play() override; + void pause() override; + bool supportsSave() const override; + void seek(double seconds) override; + void setRate(double) override; + void setVolume(double) override; + blink::WebTimeRanges buffered() const override; + blink::WebTimeRanges seekable() const override; + + void paint(blink::WebCanvas*, + const blink::WebRect&, + unsigned char alpha, + SkXfermode::Mode) override; + + // True if the loaded media has a playable video/audio track. + bool hasVideo() const override; + bool hasAudio() const override; + + // Dimension of the video. + blink::WebSize naturalSize() const override; + + // Getters of playback state. + bool paused() const override; + bool seeking() const override; + double duration() const override; + double currentTime() const override; + + // Internal states of loading and network. + NetworkState networkState() const override; + ReadyState readyState() const override; + + bool didLoadingProgress() override; + + bool hasSingleSecurityOrigin() const override; + bool didPassCORSAccessCheck() const override; + + double mediaTimeForTimeValue(double timeValue) const override; + + unsigned decodedFrameCount() const override; + unsigned droppedFrameCount() const override; + unsigned audioDecodedByteCount() const override; + unsigned videoDecodedByteCount() const override; + + // cc::VideoFrameProvider implementation. + void SetVideoFrameProviderClient( + cc::VideoFrameProvider::Client* client) override; + scoped_refptr GetCurrentFrame() override; + void PutCurrentFrame( + const scoped_refptr& frame) override {}; + + // Method inherited from DestructionObserver. + void WillDestroyCurrentMessageLoop() override {}; + + virtual MediaKeyException generateKeyRequest( + const blink::WebString& key_system, + const unsigned char* init_data, + unsigned init_data_length); + + virtual MediaKeyException addKey(const blink::WebString& key_system, + const unsigned char* key, + unsigned key_length, + const unsigned char* init_data, + unsigned init_data_length, + const blink::WebString& session_id); + + virtual MediaKeyException cancelKeyRequest( + const blink::WebString& key_system, + const blink::WebString& session_id); + + // TODO(jrummell): Remove this method once Blink updated to use the other + // method. + virtual void setContentDecryptionModule( + blink::WebContentDecryptionModule* cdm); + virtual void setContentDecryptionModule( + blink::WebContentDecryptionModule* cdm, + blink::WebContentDecryptionModuleResult result); + + void SetReadyState(WebMediaPlayer::ReadyState state); + void SetNetworkState(WebMediaPlayer::NetworkState state); + + void OnNewFrameAvailable(base::SharedMemoryHandle foreign_memory_handle, + uint32 length, base::TimeDelta timestamp); + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) + void OnPlatformSurfaceUpdated(int pixmap_id, base::TimeDelta timestamp); +#endif + + void OnMediaDataChange(int format, int height, int width, int media); + void OnDurationChange(double duration); + void OnTimeUpdate(double current_time); + void OnBufferUpdate( + std::vector buffer_range); + void OnTimeChanged(); + void OnPauseStateChange(bool state); + void OnSeekStateChange(bool state); + void OnRequestSeek(double seek_time); + + void OnMediaSourceOpened(blink::WebMediaSource* web_media_source); + void OnDemuxerSeekDone(); + + void RequestPause(); + + private: + void OnNaturalSizeChanged(gfx::Size size); + void OnOpacityChanged(bool opaque); + + // Returns the current video frame from |compositor_|. Blocks until the + // compositor can return the frame. + scoped_refptr GetCurrentFrameFromCompositor(); + + // Called whenever there is new frame to be painted. + void FrameReady(const scoped_refptr& frame); + + blink::WebLocalFrame* frame_; + + blink::WebMediaPlayer::NetworkState network_state_; + blink::WebMediaPlayer::ReadyState ready_state_; + + // Message loops for posting tasks on Chrome's main thread. Also used + // for DCHECKs so methods calls won't execute in the wrong thread. + const scoped_refptr main_loop_; + scoped_refptr media_task_runner_; + + // Manager for managing this object and for delegating method calls on + // Render Thread. + content::RendererMediaPlayerManagerEfl* manager_; + + blink::WebMediaPlayerClient* client_; + + scoped_refptr media_log_; + + base::WeakPtr delegate_; + + // The compositor layer for displaying the video content when using + // composited playback. + scoped_ptr video_weblayer_; + + + // Video rendering members. + scoped_refptr compositor_task_runner_; + media::VideoFrameCompositor* compositor_; + media::SkCanvasVideoRenderer skcanvas_video_renderer_; + + base::WeakPtrFactory weak_factory_; + scoped_ptr media_source_delegate_; + MediaPlayerHostMsg_Initialize_Type player_type_; + + // Player ID assigned by the |manager_|. + int player_id_; + + uint32 gst_video_format_; + int gst_width_; + int gst_height_; + + bool FrameAvailable_; + bool audio_; + bool video_; + + double current_time_; + double duration_; + bool is_paused_; + + bool is_seeking_; + double seek_time_; + bool pending_seek_; + double pending_seek_time_; + + // Whether the video is known to be opaque or not. + bool opaque_; + + gfx::Size natural_size_; + blink::WebTimeRanges buffered_; + mutable bool did_loading_progress_; + double volume_; + + // Factories for supporting video accelerators. May be null. + scoped_refptr gpu_factories_; + scoped_ptr encrypted_media_support_; + content::WrtUrlParseBase* wrt_url_parse_; + + DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerEfl); +}; + +} // namespace media + +#endif // CONTENT_RENDERER_MEDIA_TIZEN_WEBMEDIAPLAYER_EFL_H_ diff --git a/tizen_src/chromium_impl/media/base/tizen/media_player_bridge_capi.cc b/tizen_src/chromium_impl/media/base/tizen/media_player_bridge_capi.cc new file mode 100644 index 000000000000..5d6826b1ba89 --- /dev/null +++ b/tizen_src/chromium_impl/media/base/tizen/media_player_bridge_capi.cc @@ -0,0 +1,748 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/base/tizen/media_player_bridge_capi.h" + +#include "base/basictypes.h" +#include "base/command_line.h" +#include "base/logging.h" +#include "base/memory/shared_memory.h" +#include "base/message_loop/message_loop_proxy.h" +#include "base/strings/string_util.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/common/content_switches.h" +#include "media/base/tizen/media_player_manager_tizen.h" +#include "ui/gfx/size.h" + +#if defined(OS_TIZEN_MOBILE) +#include +#endif + +namespace { +// Update duration every 100ms. +const int kDurationUpdateInterval = 100; +} + +namespace media { +struct ErrorList { + player_error_e error_code; + std::string error_message; +}; + +// Modify this when new error information is added to |errorlist|. +const int ERROR_MAX = 18; + +const struct ErrorList errorlist[ERROR_MAX] = { + {PLAYER_ERROR_OUT_OF_MEMORY, "PLAYER_ERROR_OUT_OF_MEMORY"}, + {PLAYER_ERROR_INVALID_PARAMETER, "PLAYER_ERROR_INVALID_PARAMETER"}, + {PLAYER_ERROR_NO_SUCH_FILE, "PLAYER_ERROR_NO_SUCH_FILE"}, + {PLAYER_ERROR_INVALID_OPERATION, "PLAYER_ERROR_INVALID_OPERATION"}, + {PLAYER_ERROR_FILE_NO_SPACE_ON_DEVICE, + "PLAYER_ERROR_FILE_NO_SPACE_ON_DEVICE"}, +#if defined(OS_TIZEN_MOBILE) + {PLAYER_ERROR_FEATURE_NOT_SUPPORTED_ON_DEVICE, + "PLAYER_ERROR_FEATURE_NOT_SUPPORTED_ON_DEVICE"}, +#endif + {PLAYER_ERROR_SEEK_FAILED, "PLAYER_ERROR_SEEK_FAILED"}, + {PLAYER_ERROR_INVALID_STATE, "PLAYER_ERROR_INVALID_STATE"}, + {PLAYER_ERROR_NOT_SUPPORTED_FILE, "PLAYER_ERROR_NOT_SUPPORTED_FILE"}, + {PLAYER_ERROR_INVALID_URI, "PLAYER_ERROR_INVALID_URI"}, + {PLAYER_ERROR_SOUND_POLICY, "PLAYER_ERROR_SOUND_POLICY"}, + {PLAYER_ERROR_CONNECTION_FAILED, "PLAYER_ERROR_CONNECTION_FAILED"}, + {PLAYER_ERROR_VIDEO_CAPTURE_FAILED, "PLAYER_ERROR_VIDEO_CAPTURE_FAILED"}, + {PLAYER_ERROR_DRM_EXPIRED, "PLAYER_ERROR_DRM_EXPIRED"}, + {PLAYER_ERROR_DRM_NO_LICENSE, "PLAYER_ERROR_DRM_NO_LICENSE"}, + {PLAYER_ERROR_DRM_FUTURE_USE, "PLAYER_ERROR_DRM_FUTURE_USE"}, + {PLAYER_ERROR_DRM_NOT_PERMITTED, "PLAYER_ERROR_DRM_NOT_PERMITTED"}, + {PLAYER_ERROR_RESOURCE_LIMIT, "PLAYER_ERROR_RESOURCE_LIMIT"}}; + +static Eina_Bool notify_damage_updated_cb(void* data, int type, void* event) { + MediaPlayerBridgeCapi* player = static_cast (data); + if (!player) + return ECORE_CALLBACK_PASS_ON; + + player->PlatformSurfaceUpdated(); + return ECORE_CALLBACK_PASS_ON; +} + +static double ConvertMilliSecondsToSeconds(int time) { + double seconds = static_cast(time) / + (base::Time::kMillisecondsPerSecond); + return seconds; +} + +static double ConvertSecondsToMilliSeconds(double time) { + if (time < 0) { + LOG(ERROR) << "Invalid time:" << time << " Reset to 0"; + time = 0; + } + double seconds = static_cast(time) * + (base::Time::kMillisecondsPerSecond); + return seconds; +} + +// Called by player_prepare_async() +void player_prepared_cb(void* user_data) { + MediaPlayerBridgeCapi* player = + static_cast(user_data); + + if (!player) + return; + + player->SetPixmap(); + player->ExecuteDelayedPlayerState(); +} + +// Called by player_set_x11_display_pixmap() +unsigned int pixmap_buffer_ready_cb(void *user_data) { + MediaPlayerBridgeCapi* player = + static_cast(user_data); + + if (!player) + return -1; + + return player->GetSurfaceID(); +} + +// Called by player_set_completed_cb() +void playback_complete_cb(void* user_data) { + MediaPlayerBridgeCapi* player = + static_cast(user_data); + + if (!player) + return; + + player->PlaybackCompleteUpdate(); +} + +// Called by player_set_play_position() +void seek_complete_cb(void* user_data) { + MediaPlayerBridgeCapi* player = + static_cast(user_data); + + if (!player) + return; + + player->SeekCompleteUpdate(); +} + +// Called by player_set_buffering_cb() +void changed_buffering_status_cb(int percent, void *user_data) { + MediaPlayerBridgeCapi* player = + static_cast(user_data); + + if (!player) + return; + + player->HandleBufferingStatus(percent); +} + +// Called by player_set_error_cb() +void error_cb(int error_code, void *user_data) { + MediaPlayerBridgeCapi* player = + static_cast(user_data); + + if (!player) + return; + + player->HandleError(error_code, "error_cb"); +} + +// Called by player_set_interrupted_cb() +void interrupt_cb(player_interrupted_code_e code, void *user_data) { + MediaPlayerBridgeCapi* player = + static_cast(user_data); + + if (!player) + return; + + // FIMXE: Add interrupt handling +} + +MediaPlayerBridgeCapi::MediaPlayerBridgeCapi( + int player_id, + const GURL& url, + double volume, + MediaPlayerManager* manager_in) + : MediaPlayerTizen(player_id, manager_in), + pixmap_id_(0), + efl_pixmap_(0), + m_damage(0), + m_damageHandler(NULL), + main_loop_(base::MessageLoopProxy::current()), + player_(NULL), + url_(url), + media_type_(0), + player_width_(0), + player_height_(0), + video_format_(0), + is_end_reached_(false), + is_file_url_(false), + is_paused_(true), + is_pixmap_used_(true), + is_seeking_(false), + duration_(0), + seek_duration_(0), + playback_rate_(1.0), + delayed_player_state_(0), + shared_memory_size(0) { + VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); + int ret = player_create(&player_); + if (ret == PLAYER_ERROR_NONE) { + VLOG(1) << __FUNCTION__ << " : Create Player Success."; + VLOG(1) << __FUNCTION__ << " : URL = " << url_.spec().c_str(); + player_set_uri(player_, url_.spec().c_str()); + player_set_sound_type(player_, SOUND_TYPE_MEDIA); + player_set_volume(player_, (float)volume, (float)volume); + + // Use Pixmap + ret = player_set_x11_display_pixmap(player_, + pixmap_buffer_ready_cb, this); + if (ret != PLAYER_ERROR_NONE) { + HandleError(ret, "player_set_x11_display_pixmap"); + return; + } + player_set_completed_cb(player_, playback_complete_cb, this); + player_set_buffering_cb(player_, changed_buffering_status_cb, this); + player_set_interrupted_cb(player_, interrupt_cb, this); + player_set_error_cb(player_, error_cb, this); +#if defined(OS_TIZEN_MOBILE) + player_set_display_visible (player_, true); +#else // OS_TIZEN_TV + player_set_x11_display_visible (player_, true); +#endif + if(url_.SchemeIsFile()) + is_file_url_ = true; + + manager()->OnReadyStateChange(GetPlayerId(), + MediaPlayerTizen::ReadyStateHaveEnoughData); + manager()->OnNetworkStateChange(GetPlayerId(), + MediaPlayerTizen::NetworkStateLoaded); + + } else { + HandleError(ret, "player_create"); + } +} + +MediaPlayerBridgeCapi::~MediaPlayerBridgeCapi() { + VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); +} + +void MediaPlayerBridgeCapi::Destroy() { + VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); + if (IsPlayerDestructing()) + return; + destructing_ = true; + StopCurrentTimeUpdateTimer(); + StopBufferingUpdateTimer(); + player_unset_completed_cb(player_); + player_unset_interrupted_cb(player_); + player_unset_error_cb(player_); + player_unset_buffering_cb(player_); + player_unset_subtitle_updated_cb(player_); + player_destroy(player_); + + if (m_damage) { + ecore_x_damage_free(m_damage); + m_damage = 0; + } + if (m_damageHandler) { + ecore_event_handler_del(m_damageHandler); + m_damageHandler = NULL; + } + if (efl_pixmap_.get()) { + efl_pixmap_ = NULL; + } + main_loop_->DeleteSoon(FROM_HERE, this); +} + +void MediaPlayerBridgeCapi::Play() { + VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); + if (GetPlayerState() == PLAYER_STATE_IDLE) { + if(delayed_player_state_ != 0) { + delayed_player_state_ = DELAYED_PLAYER_STATE_PLAY; + return; + } + delayed_player_state_ = DELAYED_PLAYER_STATE_PLAY; + int ret = player_prepare_async(player_, player_prepared_cb, this); + if (ret != PLAYER_ERROR_NONE) + HandleError(ret, "player_prepare_async"); + return; + } + + if (playback_rate_ == 0.0) { + is_paused_ = false; + return; + } + if (player_start(player_) != PLAYER_ERROR_NONE) { + LOG(ERROR) <<"Play() -> |player_start| failed"; + return; + } + +#if defined(OS_TIZEN_MOBILE) + if (device_power_request_lock(POWER_LOCK_DISPLAY, 0) != DEVICE_ERROR_NONE) + LOG(ERROR) <<"Play() -> |device_power_request_lock| failed"; +#endif + main_loop_->PostTask( + FROM_HERE, + base::Bind( + &MediaPlayerBridgeCapi::StartCurrentTimeUpdateTimer, + base::Unretained(this))); + if (!is_file_url_) + main_loop_->PostTask( + FROM_HERE, + base::Bind( + &MediaPlayerBridgeCapi::StartBufferingUpdateTimer, + base::Unretained(this))); + is_paused_ = false; + is_end_reached_ = false; +} + +void MediaPlayerBridgeCapi::Pause(bool is_media_related_action) { + VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); + if (GetPlayerState() == PLAYER_STATE_IDLE) { + if(delayed_player_state_ != 0) { + delayed_player_state_ = DELAYED_PLAYER_STATE_PAUSE; + return; + } + delayed_player_state_ = DELAYED_PLAYER_STATE_PAUSE; + int ret = player_prepare_async(player_, player_prepared_cb, this); + if (ret != PLAYER_ERROR_NONE) + HandleError(ret, "player_prepare_async"); + return; + } + + if (player_pause(player_) != PLAYER_ERROR_NONE) { + LOG(ERROR) << "Pause() -> |player_pause| failed"; + return; + } + + if (!is_file_url_) + main_loop_->PostTask( + FROM_HERE, + base::Bind( + &MediaPlayerBridgeCapi::StartBufferingUpdateTimer, + base::Unretained(this))); + +#if defined(OS_TIZEN_MOBILE) + if (device_power_release_lock(POWER_LOCK_DISPLAY) != DEVICE_ERROR_NONE) + LOG(ERROR) << "|device_power_release_lock| request failed"; +#endif + + StopCurrentTimeUpdateTimer(); + is_paused_ = true; +} + +void MediaPlayerBridgeCapi::SetRate(double rate) { + VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); + if (playback_rate_ == rate) + return; + + if (rate == 0.0) { + playback_rate_ = rate; + Pause(true); + return; + } + + // Fixme: SetRate is always failing + if (player_set_playback_rate(player_, (float)rate) != PLAYER_ERROR_NONE) + LOG(ERROR) <<"|player_set_playback_rate|failed"; + else { + // If previous rate was zero and requested rate is non-zero, change the + // playback rate and call play + if(playback_rate_ == 0.0 && rate != 0.0) { + playback_rate_ = rate; + Play(); + } else { + playback_rate_ = rate; + } + } +} + +void MediaPlayerBridgeCapi::Seek(const double time) { + VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); +#if defined(OS_TIZEN_MOBILE) + int err = player_set_play_position(player_, + ConvertSecondsToMilliSeconds(time), true, seek_complete_cb, this); +#else // OS_TIZEN_TV + int err = player_set_position(player_, + ConvertSecondsToMilliSeconds(time), seek_complete_cb, this); +#endif + if(err != PLAYER_ERROR_NONE) { + LOG(ERROR) <<"|player_set_playback_rate|failed"; + manager()->OnTimeUpdate(GetPlayerId(), GetCurrentTime()); + manager()->OnTimeChanged(GetPlayerId()); + return; + } + + if (!is_paused_) + StopCurrentTimeUpdateTimer(); + + StopBufferingUpdateTimer(); + UpdateSeekState(true); + seek_duration_ = time; + is_end_reached_ = time != duration_ ? false : true; + manager()->OnTimeUpdate(GetPlayerId(), time); + + if (!is_paused_) + main_loop_->PostTask( + FROM_HERE, + base::Bind( + &MediaPlayerBridgeCapi::StartCurrentTimeUpdateTimer, + base::Unretained(this))); +} + +void MediaPlayerBridgeCapi::Release() { +} + +void MediaPlayerBridgeCapi::SetVolume(double volume) { + VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId() + << " : Volume : " << volume; + if (GetPlayerState() > PLAYER_STATE_IDLE){ + if(volume == 0.0){ + if(player_set_mute(player_,true) + != PLAYER_ERROR_NONE) + LOG(ERROR) << "|player_set_mute(true)| failed in MediaPlayerBridgeCapi::" + << __FUNCTION__; + + return; + } + + if(player_set_mute(player_,false) + != PLAYER_ERROR_NONE) + LOG(ERROR) << "|player_set_mute(false)| failed in MediaPlayerBridgeCapi::" + << __FUNCTION__; + + if (player_set_volume(player_, (float)volume, (float)volume) + != PLAYER_ERROR_NONE) + LOG(ERROR) << "|player_set_volume| failed in MediaPlayerBridgeCapi::" + << __FUNCTION__; + } +} + +void MediaPlayerBridgeCapi::UpdateMediaType() { + int fps = 0 ; + int bit_rate = 0; + int sample_rate = 0; + int channel = 0; + int audio_bit_rate = 0; + media_type_ = 0; + + int err = player_get_video_stream_info(player_, &fps, &bit_rate); + int err_audio = player_get_audio_stream_info(player_, + &sample_rate, &channel, &audio_bit_rate); + + VLOG(1) << "Audio Information: sample_rate = " << sample_rate + << " , channel = " << channel + << " , audio_bit_rate = " << audio_bit_rate; + + if (err != PLAYER_ERROR_NONE) { + HandleError(err, "player_get_video_stream_info"); + return; + } + + if (err_audio != PLAYER_ERROR_NONE) { + HandleError(err_audio, "player_get_audio_stream_info"); + return; + } + + if (sample_rate > 0) + media_type_ |= MEDIA_AUDIO_MASK; + + err = player_get_video_size(player_,&player_width_,&player_height_); + if (err != PLAYER_ERROR_NONE) { + HandleError(err, " player_get_video_size"); + return; + } + + VLOG(1) << "Video Information: fps = " << fps + << " , bit_rate = " << bit_rate + << " , Video Height = " << player_height_ + << " , Video Width = " << player_width_; + + // Video stream is present if both video width and video + // height are non-zero. + if (player_width_ != 0 && player_height_ != 0) + media_type_ |= MEDIA_VIDEO_MASK; + + // Passing NULL value for video_format. Its not required but + // |webmediaplayertizen| expects a value. + manager()->OnMediaDataChange(GetPlayerId(), video_format_, player_height_, + player_width_, media_type_); +} + +void MediaPlayerBridgeCapi::UpdateDuration() { + int duration = 0; + player_get_duration(player_, &duration); + + if (duration_ != ConvertMilliSecondsToSeconds(duration)) { + duration_ = ConvertMilliSecondsToSeconds(duration); + manager()->OnDurationChange(GetPlayerId(), duration_); + } + + // No need to buffer 'local file'. Update buffered percentage. + if(is_file_url_) { + std::vector buffer_range; + media::MediaPlayerTizen::TimeRanges range; + range.start = 0; + range.end = duration_ * base::Time::kMicrosecondsPerSecond; + buffer_range.push_back(range); + manager()->OnBufferUpdate(GetPlayerId(), buffer_range); + } +} + +double MediaPlayerBridgeCapi::GetCurrentTime() { + // For http://instagram.com/p/tMQOo0lWqm/ + // After playback completed current-time and duration are not equal. + if (is_end_reached_) { + if (is_seeking_) + return seek_duration_; + if (playback_rate_ < 0) + return 0.0f; + if (duration_) + return duration_; + } + + int postion = 0; +#if defined(OS_TIZEN_MOBILE) + player_get_play_position(player_, &postion); +#else // OS_TIZEN_TV + player_get_position(player_, &postion); +#endif + return ConvertMilliSecondsToSeconds(postion); +} + +void MediaPlayerBridgeCapi::OnCurrentTimeUpdateTimerFired() { + if (IsPlayerDestructing()) + return; + manager()->OnTimeUpdate(GetPlayerId(), GetCurrentTime()); + UpdateDuration(); +} + +void MediaPlayerBridgeCapi::StartCurrentTimeUpdateTimer() { + if (!current_time_update_timer_.IsRunning()) { + current_time_update_timer_.Start( + FROM_HERE, + base::TimeDelta::FromMilliseconds(kDurationUpdateInterval), + this, &MediaPlayerBridgeCapi::OnCurrentTimeUpdateTimerFired); + } +} + +void MediaPlayerBridgeCapi::StopCurrentTimeUpdateTimer() { + if (current_time_update_timer_.IsRunning()) + current_time_update_timer_.Stop(); +} + +void MediaPlayerBridgeCapi::OnBufferingUpdateTimerFired() { + if (IsPlayerDestructing()) + return; + + int start, current; + if (player_get_streaming_download_progress(player_, + &start, ¤t) == PLAYER_ERROR_NONE) { + if (current == 100) { + StopBufferingUpdateTimer(); + manager()->OnNetworkStateChange(GetPlayerId(), + MediaPlayerTizen::NetworkStateLoaded); + } + std::vector buffer_range; + media::MediaPlayerTizen::TimeRanges range; + range.start = 0; + range.end = static_cast(current) * duration_ / 100 + * base::Time::kMicrosecondsPerSecond; + buffer_range.push_back(range); + manager()->OnBufferUpdate(GetPlayerId(), buffer_range); + } +} + +void MediaPlayerBridgeCapi::StartBufferingUpdateTimer() { + if (!buffering_update_timer_.IsRunning()) { + buffering_update_timer_.Start( + FROM_HERE, + base::TimeDelta::FromMilliseconds(kDurationUpdateInterval), + this, &MediaPlayerBridgeCapi::OnBufferingUpdateTimerFired); + } +} + +void MediaPlayerBridgeCapi::StopBufferingUpdateTimer() { + if (buffering_update_timer_.IsRunning()) + buffering_update_timer_.Stop(); +} + +void MediaPlayerBridgeCapi::OnTimeChanged() { + DCHECK(main_loop_->BelongsToCurrentThread()); + manager()->OnTimeChanged(GetPlayerId()); +} + +void MediaPlayerBridgeCapi::PlaybackCompleteUpdate() { + VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); + is_end_reached_ = true; +#if defined(OS_TIZEN_MOBILE) + if (device_power_release_lock(POWER_LOCK_DISPLAY) != DEVICE_ERROR_NONE) + LOG(ERROR) << "|device_power_release_lock| request failed"; +#endif + + StopCurrentTimeUpdateTimer(); + manager()->OnTimeUpdate(GetPlayerId(), GetCurrentTime()); + manager()->OnTimeChanged(GetPlayerId()); +} + +void MediaPlayerBridgeCapi::SeekCompleteUpdate() { + UpdateSeekState(false); + manager()->OnTimeChanged(GetPlayerId()); + + if (!is_file_url_) + main_loop_->PostTask( + FROM_HERE, + base::Bind( + &MediaPlayerBridgeCapi::StartBufferingUpdateTimer, + base::Unretained(this))); +} + +void MediaPlayerBridgeCapi::UpdateSeekState(bool state) { + is_seeking_ = state; +} + +void MediaPlayerBridgeCapi::PlatformSurfaceUpdated() { + int postion = 0; +#if defined(OS_TIZEN_MOBILE) + player_get_play_position(player_, &postion); +#else // OS_TIZEN_TV + player_get_position(player_, &postion); +#endif + base::TimeDelta timestamp = base::TimeDelta::FromMilliseconds(postion); + manager()->OnPlatformSurfaceUpdated(GetPlayerId(), pixmap_id_, timestamp); +} + +void MediaPlayerBridgeCapi::SetPixmap() { + VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); + UpdateMediaType(); + UpdateDuration(); + if (media_type_ == 0) + return; + + if ((media_type_ & MEDIA_VIDEO_MASK) && !efl_pixmap_.get()) { + efl_pixmap_ = gfx::EflPixmap::Create(gfx::EflPixmap::SURFACE, + gfx::Size(player_width_, player_height_)); + if (!efl_pixmap_.get()) { + HandleError(0, " PixmapSurfaceTizen::create"); + return ; + } + is_pixmap_used_ = true; + pixmap_id_ = efl_pixmap_->GetId(); + + //Register to get notification from ecore for damage updates. + m_damage = ecore_x_damage_new(pixmap_id_, + ECORE_X_DAMAGE_REPORT_RAW_RECTANGLES); + m_damageHandler = ecore_event_handler_add(ECORE_X_EVENT_DAMAGE_NOTIFY, + notify_damage_updated_cb, this); + } + + manager()->OnReadyStateChange(GetPlayerId(), + MediaPlayerTizen::ReadyStateHaveEnoughData); + manager()->OnNetworkStateChange(GetPlayerId(), + MediaPlayerTizen::NetworkStateLoaded); +} + +int MediaPlayerBridgeCapi::GetSurfaceID() const { + return pixmap_id_; +} + +void MediaPlayerBridgeCapi::HandleBufferingStatus(int percent) { + if (IsPlayerDestructing()) + return; + + if (percent == 100 && !is_paused_ && !is_seeking_) { + if (GetPlayerState() == PLAYER_STATE_PAUSED) { + VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId() + << " : Playing MediaPlayer as buffer reached 100%"; + if (player_start(player_) != PLAYER_ERROR_NONE) { + LOG(ERROR) << "HandleBufferingStatus:player_start failed"; + return; + } + main_loop_->PostTask( + FROM_HERE, + base::Bind( + &MediaPlayerBridgeCapi::StartCurrentTimeUpdateTimer, + base::Unretained(this))); + if (!is_file_url_) + main_loop_->PostTask( + FROM_HERE, + base::Bind( + &MediaPlayerBridgeCapi::StartBufferingUpdateTimer, + base::Unretained(this))); + manager()->OnReadyStateChange(GetPlayerId(), + MediaPlayerTizen::ReadyStateHaveEnoughData); + manager()->OnNetworkStateChange(GetPlayerId(), + MediaPlayerTizen::NetworkStateLoading); + return; + } + } + + if (percent != 100 && !is_paused_ && !is_seeking_) { + if (GetPlayerState() == PLAYER_STATE_PLAYING) { + VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId() + << " : Pausing MediaPlayer as buffer is < 100%"; + if (player_pause(player_) != PLAYER_ERROR_NONE) { + LOG(ERROR) << "HandleBufferingStatus:player_pause failed"; + return; + } + StopCurrentTimeUpdateTimer(); + manager()->OnReadyStateChange(GetPlayerId(), + MediaPlayerTizen::ReadyStateHaveCurrentData); + manager()->OnNetworkStateChange(GetPlayerId(), + MediaPlayerTizen::NetworkStateLoading); + } + } +} + +// Helper method which prints errors occured while calling CAPI api's. +void MediaPlayerBridgeCapi::HandleError(int err, char const* from) { + int index; + for (index = 0; index < ERROR_MAX; index++) { + if (errorlist[index].error_code == err) { + LOG(ERROR) << "Stoping playback of media due to Error code : "<OnNetworkStateChange(GetPlayerId(), + MediaPlayerTizen::NetworkStateDecodeError); + +#ifdef OS_TIZEN_MOBILE + if (device_power_release_lock(POWER_LOCK_DISPLAY) != DEVICE_ERROR_NONE) + LOG(ERROR) << "|device_power_release_lock| request failed"; +#endif +} + +player_state_e MediaPlayerBridgeCapi::GetPlayerState() { + player_state_e state; + player_get_state(player_,&state); + return state; +} + +void MediaPlayerBridgeCapi::ExecuteDelayedPlayerState() { + switch (delayed_player_state_) { + case DELAYED_PLAYER_STATE_PLAY : + VLOG(1) << "Executing the delayed play command"; + Play(); + break; + case DELAYED_PLAYER_STATE_PAUSE : + VLOG(1) << "Executing the delayed pause command"; + Pause(false); + break; + default : + break; + } +} + +} // namespace media diff --git a/tizen_src/chromium_impl/media/base/tizen/media_player_bridge_capi.h b/tizen_src/chromium_impl/media/base/tizen/media_player_bridge_capi.h new file mode 100644 index 000000000000..a5836e164148 --- /dev/null +++ b/tizen_src/chromium_impl/media/base/tizen/media_player_bridge_capi.h @@ -0,0 +1,125 @@ +// Copyright 2014 Samsung Electronics Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_TIZEN_MEDIA_PLAYER_BRIDGE_CAPI_H_ +#define MEDIA_TIZEN_MEDIA_PLAYER_BRIDGE_CAPI_H_ + +#include +#if defined(TIZEN_V_2_4) +#include +#else +#include +#endif + +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +#include +#include "ecore_x_wrapper.h" +#endif + +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/timer/timer.h" +#include "content/public/browser/browser_message_filter.h" +#include "media/base/ranges.h" +#include "media/base/tizen/media_player_tizen.h" +#include "media/base/video_frame.h" +#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) +#include "ui/gl/efl_pixmap.h" +#endif + +namespace media { + +class MEDIA_EXPORT MediaPlayerBridgeCapi + : public MediaPlayerTizen { + public: + MediaPlayerBridgeCapi(int player_id, + const GURL& url, + double volume, + MediaPlayerManager* manager); + virtual ~MediaPlayerBridgeCapi(); + + // MediaPlayerTizen implementation. + virtual void Destroy() override; + virtual void Play() override; + virtual void Pause(bool is_media_related_action) override; + virtual void SetRate(double rate) override; + virtual void Seek(const double time) override; + virtual void SetVolume(double volume) override; + virtual double GetCurrentTime() override; + + int GetSurfaceID() const; + void ExecuteDelayedPlayerState(); + void HandleBufferingStatus(int percent); + void HandleError(int ret, char const* from); + void PlatformSurfaceUpdated(); + void PlaybackCompleteUpdate(); + void SeekCompleteUpdate(); + void SetPixmap(); + + protected: + virtual void Release(); + + private: + // |duration_update_timer_| related + void OnCurrentTimeUpdateTimerFired(); + void StartCurrentTimeUpdateTimer(); + void StopCurrentTimeUpdateTimer(); + + // |buffering_update_timer_| related + void OnBufferingUpdateTimerFired(); + void StartBufferingUpdateTimer(); + void StopBufferingUpdateTimer(); + + void OnTimeChanged(); + void UpdateMediaType(); + void UpdateSeekState(bool state); + void UpdateDuration(); + + player_state_e GetPlayerState(); + + private: + int pixmap_id_; + scoped_refptr efl_pixmap_; + Ecore_X_Damage m_damage; + Ecore_Event_Handler* m_damageHandler; + + const scoped_refptr main_loop_; + + player_h player_; + GURL url_; + + int media_type_; + int player_width_; + int player_height_; + unsigned int video_format_; + + bool is_download_finished_; + bool is_end_reached_; + bool is_file_url_; + bool is_paused_; + bool is_pixmap_used_; + bool is_seeking_; + + double duration_; + double seek_duration_; + double playback_rate_; + + int delayed_player_state_; + const static int DELAYED_PLAYER_STATE_PLAY = 1; + const static int DELAYED_PLAYER_STATE_PAUSE = 2; + + base::SharedMemory shared_memory; + uint32 shared_memory_size; + base::SharedMemoryHandle foreign_memory_handle; + + base::RepeatingTimer current_time_update_timer_; + base::RepeatingTimer buffering_update_timer_; + + DISALLOW_COPY_AND_ASSIGN(MediaPlayerBridgeCapi); +}; + +} // namespace media + +#endif // MEDIA_TIZEN_MEDIA_PLAYER_BRIDGE_CAPI_H_ + diff --git a/tizen_src/chromium_impl/media/media_efl.gypi b/tizen_src/chromium_impl/media/media_efl.gypi new file mode 100644 index 000000000000..280604d91e48 --- /dev/null +++ b/tizen_src/chromium_impl/media/media_efl.gypi @@ -0,0 +1,86 @@ +# Copyright (c) 2015 Samsung Electronics. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +{ + 'variables': { + 'external_media_deps': [ + '<(DEPTH)/tizen_src/build/system.gyp:ecore', + '<(DEPTH)/tizen_src/build/system.gyp:ecore-x', + '<(DEPTH)/tizen_src/build/system.gyp:gstreamer', + ], + }, + + 'target_defaults': { + 'target_conditions': [ + + ['_target_name=="media"', { + 'include_dirs': [ + '<(DEPTH)/third_party/WebKit', + '<(DEPTH)/v8/include', + ], + 'sources': [ + 'base/efl/webaudio_media_codec_info_efl.h', + 'base/efl/demuxer_stream_player_params_efl.cc', + 'base/efl/demuxer_stream_player_params_efl.h', + 'base/efl/demuxer_efl.h', + 'base/efl/media_player_efl.h', + 'base/efl/media_player_bridge_gstreamer.cc', + 'base/efl/media_player_bridge_gstreamer.h', + 'base/efl/media_player_manager_efl.h', + 'base/efl/media_source_player_gstreamer.cc', + 'base/efl/media_source_player_gstreamer.h', + 'base/efl/webmediaplayer_efl.cc', + 'base/efl/webmediaplayer_efl.h', # ME and MSE + ], + + 'conditions': [ + + ['building_for_tizen_mobile==1', { + 'defines': [ + 'TIZEN_VIDEO_CAPTURE_SUPPORT=1', + ], + 'sources/': [ + [ 'exclude', 'video/capture/linux/video_capture_device_factory_linux.cc$' ], + [ 'exclude', 'video/capture/linux/video_capture_device_factory_linux.h$' ], + [ 'exclude', 'video/capture/linux/video_capture_device_linux.h$' ], + [ 'exclude', 'video/capture/linux/video_capture_device_linux.cc$' ], + ], + 'sources': [ + 'video/capture/tizen/video_capture_device_tizen.cc', + 'video/capture/tizen/video_capture_device_tizen.h', + 'video/capture/tizen/video_capture_device_factory_tizen.cc', + 'video/capture/tizen/video_capture_device_factory_tizen.h', + 'video/capture/tizen/video_capture_device_factory_tizen_helper.cc', + ], + }], + + ['building_for_tizen_tv==1 and chromium_efl_tizen_version!="3.0"', { + 'sources': [ + 'audio/tizen/audio_session_manager.h', + 'audio/tizen/audio_session_manager.cc', # ASM + ], + }], + + ['tizen_multimedia_use_capi_for_me==1', { + 'defines': [ + 'TIZEN_CAPI_PLAYER_SUPPORT=1', + ], + 'sources': [ + 'base/tizen/media_player_bridge_capi.cc', + 'base/tizen/media_player_bridge_capi.h', # ME with CAPI-MEDIA-PLAYER + ], + # Exclude the sources that depend on CAPI-MEDIA-PLAYER + 'sources!': [ + 'base/efl/media_player_bridge_gstreamer.cc', + 'base/efl/media_player_bridge_gstreamer.h', # ME with Gstreamer + ], + }], + + ], # conditions + + }], # _target_name=="media" + + ], # target_conditions + }, # target_defaults +} diff --git a/tizen_src/chromium_impl/media/video/capture/tizen/video_capture_device_factory_tizen.cc b/tizen_src/chromium_impl/media/video/capture/tizen/video_capture_device_factory_tizen.cc new file mode 100644 index 000000000000..5ebec8b237a6 --- /dev/null +++ b/tizen_src/chromium_impl/media/video/capture/tizen/video_capture_device_factory_tizen.cc @@ -0,0 +1,246 @@ +// Copyright 2014 The Samsung 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 "media/video/capture/tizen/video_capture_device_factory_tizen.h" + +#include + +#include "media/video/capture/tizen/video_capture_device_tizen.h" + +namespace { + +enum { kMaxWidth = 1280 }; +enum { kMaxHeight = 720 }; +enum { kMaxFramerate = CAMERA_ATTR_FPS_30 }; + +media::VideoPixelFormat toChromiumType(camera_pixel_format_e e) { + switch (e) { + case CAMERA_PIXEL_FORMAT_NV12: + return media::PIXEL_FORMAT_NV12; + case CAMERA_PIXEL_FORMAT_NV21: + return media::PIXEL_FORMAT_NV21; + case CAMERA_PIXEL_FORMAT_YUYV: + return media::PIXEL_FORMAT_YUY2; + case CAMERA_PIXEL_FORMAT_RGB888: + return media::PIXEL_FORMAT_RGB24; + case CAMERA_PIXEL_FORMAT_UYVY: + return media::PIXEL_FORMAT_UYVY; + case CAMERA_PIXEL_FORMAT_ARGB: + return media::PIXEL_FORMAT_ARGB; + case CAMERA_PIXEL_FORMAT_I420: + return media::PIXEL_FORMAT_I420; + case CAMERA_PIXEL_FORMAT_YV12: + return media::PIXEL_FORMAT_YV12; + case CAMERA_PIXEL_FORMAT_JPEG: + return media::PIXEL_FORMAT_MJPEG; + default: + NOTREACHED(); + } + return media::PIXEL_FORMAT_UNKNOWN; +} + +bool OnCameraSupportedPreviewResolution( + int width, int height, void* user_data) { + std::vector* sizes = + static_cast< std::vector* >(user_data); + DCHECK(sizes); + + if ((width > kMaxWidth && height > kMaxHeight) || + (height > kMaxWidth && width > kMaxHeight)) { + return true; + } + + sizes->push_back(gfx::Size(width, height)); + + return true; +} + +bool OnCameraSupportedPreviewFormat( + camera_pixel_format_e format, void* user_data) { + std::vector* list_format = + static_cast< std::vector* >(user_data); + DCHECK(list_format); + + list_format->push_back(toChromiumType(format)); + + return true; +} + +bool OnCameraSupportedFPS(camera_attr_fps_e fps, void* user_data) { + std::vector* list_fps = static_cast< std::vector* >(user_data); + DCHECK(list_fps); + if (CAMERA_ATTR_FPS_AUTO != fps && kMaxFramerate >= fps) { + // AUTO format is not defined on Chromium, so skip. + list_fps->push_back(static_cast(fps)); + } + + return true; +} + +void GenerateChromiumVideoCaptureFormat( + const std::vector& frame_sizes, + const std::vector& fps, + const std::vector& formats, + std::vector& outSupportedFormats) { + for (auto itrS = frame_sizes.begin(); itrS != frame_sizes.end(); itrS++) { + for (auto itrFPS = fps.begin(); itrFPS != fps.end(); itrFPS++) { + for (auto itrFMT = formats.begin(); itrFMT != formats.end(); itrFMT++) { + media::VideoCaptureFormat format; + format.frame_size = *itrS; + format.frame_rate = *itrFPS; + format.pixel_format = *itrFMT; + outSupportedFormats.push_back(format); + + LOG(INFO) << __FUNCTION__ + << " frame_size:" << format.frame_size.width() << "X" << format.frame_size.height() + << " frame_rate:" << format.frame_rate + << " pixel_format:" << format.pixel_format; + } + } + } +} + +class CameraHandle final { + public: + explicit CameraHandle(const media::VideoCaptureDevice::Name& dev) + : camera_handle_(NULL) { + if (!dev.id().empty()) + if (CAMERA_ERROR_NONE != camera_create( + media::VideoCaptureDeviceTizen::DeviceNameToCameraId(dev), + &camera_handle_)) { + camera_handle_ = NULL; + LOG(ERROR) << "Cannot create camera"; + } + } + + CameraHandle() + : camera_handle_(NULL) { + if (CAMERA_ERROR_NONE != camera_create(CAMERA_DEVICE_CAMERA0, &camera_handle_)) { + camera_handle_ = NULL; + LOG(ERROR) << "Cannot create camera"; + } + } + + ~CameraHandle() { + if (camera_handle_ != NULL) + camera_destroy(camera_handle_); + } + + bool IsValid() const { + return camera_handle_ != NULL; + } + + void GetDeviceSupportedFormats( + media::VideoCaptureFormats& supported_formats) const { + std::vector supported_frame_sizes; + std::vector supported_frame_rates; + std::vector supported_pixel_formats; + + if (!IsValid()) { + LOG(ERROR) << "Cannot use camera"; + return; + } + + if (CAMERA_ERROR_NONE != camera_foreach_supported_preview_resolution( + camera_handle_, + OnCameraSupportedPreviewResolution, + &supported_frame_sizes)) { + LOG(ERROR) << "Cannot get the supported resolutions for camera"; + return; + } + + if (CAMERA_ERROR_NONE != camera_foreach_supported_preview_format( + camera_handle_, + OnCameraSupportedPreviewFormat, + &supported_pixel_formats)) { + LOG(ERROR) << "Cannot get the supported formats for camera"; + return; + } + + if (CAMERA_ERROR_NONE != camera_attr_foreach_supported_fps( + camera_handle_, + OnCameraSupportedFPS, + &supported_frame_rates)) { + LOG(ERROR) << "Cannot get the supported FPS for camera"; + return; + } + supported_formats.clear(); + GenerateChromiumVideoCaptureFormat(supported_frame_sizes, + supported_frame_rates, + supported_pixel_formats, + supported_formats); + } + + int GetDeviceCounts() const { + int device_count = 0; + if (CAMERA_ERROR_NONE != + camera_get_device_count(camera_handle_, &device_count)) { + device_count = 0; + LOG(ERROR) << "Cannot read camera count"; + } + return device_count; + } + + private: + camera_h camera_handle_; +}; + +} // namespace + +namespace media { + +VideoCaptureDeviceFactoryTizen::VideoCaptureDeviceFactoryTizen( + scoped_refptr ui_task_runner) + : ui_task_runner_(ui_task_runner) { +} + +VideoCaptureDeviceFactoryTizen::~VideoCaptureDeviceFactoryTizen() { +} + +scoped_ptr VideoCaptureDeviceFactoryTizen::Create( + const VideoCaptureDevice::Name& name) { + DCHECK(thread_checker_.CalledOnValidThread()); + + return scoped_ptr(new VideoCaptureDeviceTizen(name)); +} + +void VideoCaptureDeviceFactoryTizen::GetDeviceNames( + VideoCaptureDevice::Names* const device_names) { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(device_names->empty()); + VideoCaptureDevice::Name primary_camera( + VideoCaptureDeviceTizen::kBackCameraName, + VideoCaptureDeviceTizen::kBackCameraId); + CameraHandle camera_handle; + + if (!camera_handle.IsValid()) { + LOG(ERROR) << "Cannot use camera"; + return; + } + + int device_count = camera_handle.GetDeviceCounts(); + if (device_count == 0) { + LOG(ERROR) << "No camera on this device."; + return; + } + + device_names->push_back(primary_camera); + if (device_count == 2) { + VideoCaptureDevice::Name secondary_camera( + VideoCaptureDeviceTizen::kFrontCameraName, + VideoCaptureDeviceTizen::kFrontCameraId); + device_names->push_back(secondary_camera); + } +} + +void VideoCaptureDeviceFactoryTizen::GetDeviceSupportedFormats( + const VideoCaptureDevice::Name& device, + VideoCaptureFormats* supported_formats) { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(supported_formats != NULL); + CameraHandle camera_handle; + camera_handle.GetDeviceSupportedFormats(*supported_formats); +} + +} // namespace media diff --git a/tizen_src/chromium_impl/media/video/capture/tizen/video_capture_device_factory_tizen.h b/tizen_src/chromium_impl/media/video/capture/tizen/video_capture_device_factory_tizen.h new file mode 100644 index 000000000000..094ae5458a68 --- /dev/null +++ b/tizen_src/chromium_impl/media/video/capture/tizen/video_capture_device_factory_tizen.h @@ -0,0 +1,38 @@ +// Copyright 2014 The Samsung Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Implementation of a VideoCaptureDeviceFactoryTizen class. + +#ifndef MEDIA_VIDEO_CAPTURE_TIZEN_VIDEO_CAPTURE_DEVICE_FACTORY_TIZEN_H_ +#define MEDIA_VIDEO_CAPTURE_TIZEN_VIDEO_CAPTURE_DEVICE_FACTORY_TIZEN_H_ + +#include "media/video/capture/video_capture_device_factory.h" + +namespace media { + +// Extension of VideoCaptureDeviceFactory to create and manipulate Tizen +// devices. +class MEDIA_EXPORT VideoCaptureDeviceFactoryTizen + : public VideoCaptureDeviceFactory { + public: + explicit VideoCaptureDeviceFactoryTizen( + scoped_refptr ui_task_runner); + ~VideoCaptureDeviceFactoryTizen() override; + + scoped_ptr Create( + const VideoCaptureDevice::Name& device_name) override; + void GetDeviceNames(VideoCaptureDevice::Names* device_names) override; + void GetDeviceSupportedFormats( + const VideoCaptureDevice::Name& device, + VideoCaptureFormats* supported_formats) override; + + private: + scoped_refptr ui_task_runner_; + + DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceFactoryTizen); +}; + +} // namespace media + +#endif // MEDIA_VIDEO_CAPTURE_TIZEN_VIDEO_CAPTURE_DEVICE_FACTORY_TIZEN_H_ diff --git a/tizen_src/chromium_impl/media/video/capture/tizen/video_capture_device_factory_tizen_helper.cc b/tizen_src/chromium_impl/media/video/capture/tizen/video_capture_device_factory_tizen_helper.cc new file mode 100644 index 000000000000..0054beda6fa2 --- /dev/null +++ b/tizen_src/chromium_impl/media/video/capture/tizen/video_capture_device_factory_tizen_helper.cc @@ -0,0 +1,24 @@ +// Copyright 2014 The Samsung Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#if defined(TIZEN_VIDEO_CAPTURE_SUPPORT) +#include "media/video/capture/tizen/video_capture_device_factory_tizen.h" +#else +#include "media/video/capture/linux/video_capture_device_factory_linux.h" +#endif + +namespace media { + +scoped_ptr CreateVideoCaptureDeviceFactoryTizen( + scoped_refptr ui_task_runner) { +#if defined(TIZEN_VIDEO_CAPTURE_SUPPORT) + return scoped_ptr( + new VideoCaptureDeviceFactoryTizen(ui_task_runner)); +#else + return scoped_ptr( + new VideoCaptureDeviceFactoryLinux(ui_task_runner)); +#endif +} + +} // namespace media diff --git a/tizen_src/chromium_impl/media/video/capture/tizen/video_capture_device_tizen.cc b/tizen_src/chromium_impl/media/video/capture/tizen/video_capture_device_tizen.cc new file mode 100644 index 000000000000..914178c99e02 --- /dev/null +++ b/tizen_src/chromium_impl/media/video/capture/tizen/video_capture_device_tizen.cc @@ -0,0 +1,336 @@ +// Copyright (c) 2012 The Samsung 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 "media/video/capture/tizen/video_capture_device_tizen.h" + +#include "eweb_view.h" + +//#define WEBRTC_DEBUG_DUMPFILE + +#if defined(WEBRTC_DEBUG_DUMPFILE) +#include +#include +int fd; +#endif + +namespace { + +enum { kMjpegWidth = 640 }; +enum { kMjpegHeight = 480 }; +enum { kTypicalFramerate = 30 }; + +camera_pixel_format_e toCapiType(media::VideoPixelFormat e) { + switch (e) { + case media::PIXEL_FORMAT_NV12: + return CAMERA_PIXEL_FORMAT_NV12; + case media::PIXEL_FORMAT_NV21: + return CAMERA_PIXEL_FORMAT_NV21; + case media::PIXEL_FORMAT_YUY2: + return CAMERA_PIXEL_FORMAT_YUYV; + case media::PIXEL_FORMAT_RGB24: + return CAMERA_PIXEL_FORMAT_RGB888; + case media::PIXEL_FORMAT_UYVY: + return CAMERA_PIXEL_FORMAT_UYVY; + case media::PIXEL_FORMAT_ARGB: + return CAMERA_PIXEL_FORMAT_ARGB; + case media::PIXEL_FORMAT_I420: + return CAMERA_PIXEL_FORMAT_I420; + case media::PIXEL_FORMAT_YV12: + return CAMERA_PIXEL_FORMAT_YV12; + case media::PIXEL_FORMAT_MJPEG: + return CAMERA_PIXEL_FORMAT_JPEG; + default: + NOTREACHED(); + } + return CAMERA_PIXEL_FORMAT_INVALID; +} + +std::string toString(camera_pixel_format_e e) { + switch (e) { + case CAMERA_PIXEL_FORMAT_NV12: + return std::string("CAMERA_PIXEL_FORMAT_NV12"); + case CAMERA_PIXEL_FORMAT_NV12T: + return std::string("CAMERA_PIXEL_FORMAT_NV12T"); + case CAMERA_PIXEL_FORMAT_NV16: + return std::string("CAMERA_PIXEL_FORMAT_NV12T"); + case CAMERA_PIXEL_FORMAT_NV21: + return std::string("CAMERA_PIXEL_FORMAT_NV21"); + case CAMERA_PIXEL_FORMAT_YUYV: + return std::string("CAMERA_PIXEL_FORMAT_YUYV"); + case CAMERA_PIXEL_FORMAT_UYVY: + return std::string("CAMERA_PIXEL_FORMAT_YUYV"); + case CAMERA_PIXEL_FORMAT_422P: + return std::string("CAMERA_PIXEL_FORMAT_422P"); + case CAMERA_PIXEL_FORMAT_I420: + return std::string("CAMERA_PIXEL_FORMAT_I420"); + case CAMERA_PIXEL_FORMAT_YV12: + return std::string("CAMERA_PIXEL_FORMAT_YV12"); + case CAMERA_PIXEL_FORMAT_RGB565: + return std::string("CAMERA_PIXEL_FORMAT_RGB565"); + case CAMERA_PIXEL_FORMAT_RGB888: + return std::string("CAMERA_PIXEL_FORMAT_RGB888"); + case CAMERA_PIXEL_FORMAT_RGBA: + return std::string("CAMERA_PIXEL_FORMAT_RGBA"); + case CAMERA_PIXEL_FORMAT_ARGB: + return std::string("CAMERA_PIXEL_FORMAT_ARGB"); + case CAMERA_PIXEL_FORMAT_JPEG: + return std::string("CAMERA_PIXEL_FORMAT_JPEG"); + default: + case CAMERA_PIXEL_FORMAT_INVALID: + return std::string("CAMERA_PIXEL_FORMAT_JPEG"); + break; + } + return std::string(); +} + +bool OnPreviewFormat( + camera_pixel_format_e format, void* user_data) { + std::vector* list_format = + static_cast< std::vector* >(user_data); + DCHECK(list_format); + + list_format->push_back(format); + + return true; +} + +} // unnamed namespace + +namespace media { + +const std::string VideoCaptureDeviceTizen::kFrontCameraName = "front"; +const std::string VideoCaptureDeviceTizen::kBackCameraName = "back"; +const std::string VideoCaptureDeviceTizen::kFrontCameraId = "1"; +const std::string VideoCaptureDeviceTizen::kBackCameraId = "0"; + +const std::string VideoCaptureDevice::Name::GetModel() const { + return "tizen camera"; +} + +VideoCaptureDeviceTizen::VideoCaptureDeviceTizen(const Name& device_name) + : state_(kIdle), + device_name_(device_name), + worker_("VideoCapture"), + buffer_(), + camera_(NULL) { +#if defined(WEBRTC_DEBUG_DUMPFILE) + LOG(INFO) << __FUNCTION__ << " DUMP OUTPUT to file: /opt/usr/dump.yuv"; + fd = open( "/opt/usr/dump.yuv", O_WRONLY | O_CREAT | O_EXCL, 0644); +#endif +} + +VideoCaptureDeviceTizen::~VideoCaptureDeviceTizen() { + state_ = kIdle; + DCHECK(!worker_.IsRunning()); +} + +void VideoCaptureDeviceTizen::AllocateAndStart( + const VideoCaptureParams& params, + scoped_ptr client) { + DCHECK(!worker_.IsRunning()); + worker_.Start(); + worker_.message_loop()->PostTask( + FROM_HERE, + base::Bind(&VideoCaptureDeviceTizen::OnAllocateAndStart, + base::Unretained(this), + params.requested_format.frame_size.width(), + params.requested_format.frame_size.height(), + params.requested_format.frame_rate, + params.requested_format.pixel_format, + base::Passed(&client))); +} + +void VideoCaptureDeviceTizen::StopAndDeAllocate() { + DCHECK(worker_.IsRunning()); + worker_.message_loop()->PostTask( + FROM_HERE, + base::Bind(&VideoCaptureDeviceTizen::OnStopAndDeAllocate, + base::Unretained(this))); + worker_.Stop(); + DeAllocateVideoBuffers(); +} + +camera_device_e VideoCaptureDeviceTizen::DeviceNameToCameraId( + const VideoCaptureDevice::Name& device_name) { + if (kBackCameraId == device_name.id()) { + return CAMERA_DEVICE_CAMERA0; + } else if (kFrontCameraId == device_name.id()) { + return CAMERA_DEVICE_CAMERA1; + } else { + NOTREACHED(); + } + return static_cast(-1); +} + +void VideoCaptureDeviceTizen::OnCameraCaptured(camera_preview_data_s* frame, + void* data) { + VideoCaptureDeviceTizen* self = static_cast(data); + camera_attr_fps_e current_fps = + static_cast(kTypicalFramerate); + camera_attr_get_preview_fps(self->camera_, ¤t_fps); + + LOG(INFO) << __FUNCTION__ + << " width:" << frame->width + << " height:" << frame->height + << " format:" << toString(frame->format); + +#if defined(OS_TIZEN_MOBILE) + int orientation = EWebView::GetOrientation(); +#else + int orientation = 0; +#endif + int length = frame->data.triple_plane.y_size + + frame->data.triple_plane.u_size + frame->data.triple_plane.v_size; + + LOG(INFO) << __FUNCTION__ << " orientation:" << orientation; + +#if defined(WEBRTC_DEBUG_DUMPFILE) + int written = write(fd, frame->data.triple_plane.y, length); + LOG(INFO) << __FUNCTION__ << " " << written << " bytes written to dump file"; +#endif + + VideoCaptureFormat capture_format_; + capture_format_.frame_size.SetSize(frame->width, frame->height); + capture_format_.frame_rate = current_fps; + capture_format_.pixel_format = PIXEL_FORMAT_I420; + self->client_->OnIncomingCapturedData( + reinterpret_cast(frame->data.triple_plane.y), + length, + capture_format_, + orientation + 90, + base::TimeTicks::Now()); +} + +void VideoCaptureDeviceTizen::OnAllocateAndStart(int width, + int height, + int frame_rate, + VideoPixelFormat format, + scoped_ptr client) { + LOG(INFO) << __FUNCTION__ + << " width:" << width + << " height:" << height + << " frame_rate:" << frame_rate + << " format:" << VideoCaptureFormat::PixelFormatToString(format); + + DCHECK_EQ(worker_.message_loop(), base::MessageLoop::current()); + + client_ = client.Pass(); + int status = CAMERA_ERROR_NONE; + + if (CAMERA_ERROR_NONE != + camera_create(DeviceNameToCameraId(device_name_), &camera_)) { + LOG(ERROR) << "Fail to create camera"; + SetErrorState("Fail to create camera"); + return; + } + + // TODO(max): camera rotation is not working in this moment. + // Need to check after CAPI's investigation. +// if (CAMERA_ERROR_NONE != +// (status = camera_attr_set_stream_rotation(camera_, CAMERA_ROTATION_90))) { +// LOG(WARNING) << " Fail to rotate camera to" << CAMERA_ROTATION_90 +// << " camera_error_e:" << status; +// SetErrorState("Camera internal Error"); +// } + + if (CAMERA_ERROR_NONE != + camera_set_display(camera_, CAMERA_DISPLAY_TYPE_NONE, NULL)) { + LOG(ERROR) << "Fail to set using camera buffer"; + SetErrorState("Camera internal Error"); + return; + } + + if (CAMERA_ERROR_NONE != + camera_set_preview_resolution(camera_, width, height)) { + LOG(WARNING) << "trying default resolution: " + << kMjpegWidth << " x " << kMjpegHeight; + + if (CAMERA_ERROR_NONE != + camera_set_preview_resolution(camera_, kMjpegWidth, kMjpegHeight)) { + LOG(ERROR) << "fail to try default resolution: " + << kMjpegWidth << " x " << kMjpegHeight; + SetErrorState("Camera internal Error"); + return; + } + } + + if (CAMERA_ERROR_NONE != + camera_set_preview_format(camera_, toCapiType(format))) { + std::vector supported_formats; + if (CAMERA_ERROR_NONE != + camera_foreach_supported_preview_format( + camera_, OnPreviewFormat, &supported_formats)) { + LOG(ERROR) << "Cannot get the supported formats for camera"; + SetErrorState("Camera internal Error"); + return; + } + if (supported_formats.empty()) { + LOG(ERROR) << "Cannot get the supported formats for camera"; + SetErrorState("Camera internal Error"); + return; + } + if (CAMERA_ERROR_NONE != + camera_set_preview_format(camera_, supported_formats[0])) { + LOG(ERROR) << "fail to set preview format: " << supported_formats[0]; + SetErrorState("Camera internal Error"); + return; + } + } + + if (CAMERA_ERROR_NONE != + camera_set_preview_cb(camera_, OnCameraCaptured, this)) { + SetErrorState("Camera internal Error"); + return; + } + + if (CAMERA_ERROR_NONE != + camera_attr_set_preview_fps( + camera_, static_cast(frame_rate))) { + LOG(WARNING) << "Camera does not support frame rate:" << frame_rate; + LOG(WARNING) << "trying default frame rate: " << kTypicalFramerate; + if (CAMERA_ERROR_NONE != + camera_attr_set_preview_fps( + camera_, static_cast(kTypicalFramerate))) { + SetErrorState("Camera internal Error"); + return; + } + } + + state_ = kCapturing; + + if (CAMERA_ERROR_NONE != camera_start_preview(camera_)) { + LOG(ERROR) << "Fail to start camera"; + SetErrorState("Camera internal Error"); + } +} + +void VideoCaptureDeviceTizen::OnStopAndDeAllocate() { + DCHECK_EQ(worker_.message_loop(), base::MessageLoop::current()); + + camera_stop_preview(camera_); + camera_destroy(camera_); + DeAllocateVideoBuffers(); + + state_ = kIdle; + client_.reset(); +} + +// TODO(max): Need to find a way how to avoid memcpy by introducing shm holding. +bool VideoCaptureDeviceTizen::AllocateVideoBuffers(int width, int height) { + /* Nothing to do */ + return true; +} + +void VideoCaptureDeviceTizen::DeAllocateVideoBuffers() { + /* Nothing to do */ +} + +void VideoCaptureDeviceTizen::SetErrorState(const std::string& reason) { + DCHECK(!worker_.IsRunning() || + worker_.message_loop() == base::MessageLoop::current()); + state_ = kError; + client_->OnError(reason); +} + +} // namespace media diff --git a/tizen_src/chromium_impl/media/video/capture/tizen/video_capture_device_tizen.h b/tizen_src/chromium_impl/media/video/capture/tizen/video_capture_device_tizen.h new file mode 100644 index 000000000000..b910505a1d79 --- /dev/null +++ b/tizen_src/chromium_impl/media/video/capture/tizen/video_capture_device_tizen.h @@ -0,0 +1,68 @@ +// Copyright (c) 2012 The Samsung Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Tizen specific implementation of VideoCaptureDevice. +// Tizen Core API is used to capture the video frames from the device. + +#ifndef MEDIA_VIDEO_CAPTURE_TIZEN_VIDEO_CAPTURE_DEVICE_TIZEN_H_ +#define MEDIA_VIDEO_CAPTURE_TIZEN_VIDEO_CAPTURE_DEVICE_TIZEN_H_ + +#include + +#include "base/threading/thread.h" +#include "media/video/capture/video_capture_device.h" + +namespace media { + +class VideoCaptureDeviceTizen : public VideoCaptureDevice { + public: + const static std::string kFrontCameraName; + const static std::string kBackCameraName; + const static std::string kFrontCameraId; + const static std::string kBackCameraId; + + explicit VideoCaptureDeviceTizen(const Name& device_name); + virtual ~VideoCaptureDeviceTizen() override; + + virtual void AllocateAndStart(const VideoCaptureParams& params, + scoped_ptr client) override; + + virtual void StopAndDeAllocate() override; + + static camera_device_e DeviceNameToCameraId( + const VideoCaptureDevice::Name& device_name); + + private: + enum InternalState { + kIdle, // The device driver is opened but camera is not in use. + kCapturing, // Video is being captured. + kError // Error accessing HW functions. + // User needs to recover by destroying the object. + }; + + static void OnCameraCaptured(camera_preview_data_s* frame, void* data); + void OnAllocateAndStart(int width, + int height, + int frame_rate, + VideoPixelFormat format, + scoped_ptr client); + void OnStopAndDeAllocate(); + + bool AllocateVideoBuffers(int width, int height); + void DeAllocateVideoBuffers(); + void SetErrorState(const std::string& reason); + + InternalState state_; + scoped_ptr client_; + Name device_name_; + base::Thread worker_; // Thread used for reading data from the device. + scoped_refptr buffer_; + camera_h camera_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(VideoCaptureDeviceTizen); +}; + +} // namespace media + +#endif // MEDIA_VIDEO_CAPTURE_TIZEN_VIDEO_CAPTURE_DEVICE_TIZEN_H_ diff --git a/tizen_src/impl/cache_params_efl.h b/tizen_src/impl/cache_params_efl.h deleted file mode 100644 index 449d1e385059..000000000000 --- a/tizen_src/impl/cache_params_efl.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2014 Samsung Electronics. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CACHE_PARAMS_EFL_H_ -#define CACHE_PARAMS_EFL_H_ - -struct CacheParamsEfl { - int64 cache_total_capacity; - int64 cache_min_dead_capacity; - int64 cache_max_dead_capacity; -#if 0 - double dead_decoded_data_deletion_interval; - int64 page_cache_capacity; - int64 url_cache_memory_capacity; - int64 url_cache_disk_capacity; -#endif -}; - -#endif /* CACHE_PARAMS_EFL_H_ */ diff --git a/tizen_src/impl/common/message_generator_efl.cc b/tizen_src/impl/common/message_generator_efl.cc deleted file mode 100644 index b30c518fb192..000000000000 --- a/tizen_src/impl/common/message_generator_efl.cc +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2014 Samsung Electronics. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Get basic type definitions. -#define IPC_MESSAGE_IMPL -#include "common/message_generator_efl.h" - -// Generate constructors. -#include "ipc/struct_constructor_macros.h" -#include "common/message_generator_efl.h" - -// Generate destructors. -#include "ipc/struct_destructor_macros.h" -#include "common/message_generator_efl.h" - -// Generate param traits write methods. -#include "ipc/param_traits_write_macros.h" -namespace IPC { -#include "common/message_generator_efl.h" -} // namespace IPC - -// Generate param traits read methods. -#include "ipc/param_traits_read_macros.h" -namespace IPC { -#include "common/message_generator_efl.h" -} // namespace IPC - -// Generate param traits log methods. -#include "ipc/param_traits_log_macros.h" -namespace IPC { -#include "common/message_generator_efl.h" -} // namespace IPC diff --git a/tizen_src/impl/common/message_generator_efl.h b/tizen_src/impl/common/message_generator_efl.h deleted file mode 100755 index abf206ea13bf..000000000000 --- a/tizen_src/impl/common/message_generator_efl.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2014 Samsung Electronics. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Multiply-included file, hence no include guard. -// efl message generator - -#include "common/render_messages_efl.h" -#include "components/editing/content/common/editing_messages.h" -#if defined(OS_TIZEN_MOBILE) -#include "common/tts_messages_efl.h" -#endif diff --git a/tizen_src/impl/common/render_messages_efl.h b/tizen_src/impl/common/render_messages_efl.h deleted file mode 100644 index f30b4a39aadf..000000000000 --- a/tizen_src/impl/common/render_messages_efl.h +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright 2014 Samsung Electronics. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Multiply-included file, no traditional include guard. - -#include "base/values.h" -#include "ipc/ipc_message_macros.h" -#include "ipc/ipc_channel_handle.h" -#include "content/public/common/common_param_traits.h" -#include "content/public/common/referrer.h" -#include "ui/gfx/ipc/gfx_param_traits.h" -#include "API/ewk_hit_test_private.h" -#include "API/ewk_text_style_private.h" -#include "cache_params_efl.h" -#include "navigation_policy_params.h" -#include "renderer/print_pages_params.h" -#include "third_party/WebKit/public/web/WebNavigationPolicy.h" -#include "third_party/WebKit/public/web/WebNavigationType.h" -#include "third_party/WebKit/public/web/WebViewModeEnums.h" -#include "ui/gfx/ipc/gfx_param_traits.h" -#include "url/gurl.h" - -#include "tizen_webview/public/tw_content_security_policy.h" -#include "tizen_webview/public/tw_error.h" -#include "tizen_webview/public/tw_hit_test.h" -#include "tizen_webview/public/tw_settings.h" -#include "tizen_webview/public/tw_wrt.h" - -#include -#include - -#if defined(TIZEN_MULTIMEDIA_SUPPORT) -#include "base/file_descriptor_posix.h" -#include "base/memory/shared_memory.h" -#endif - -typedef std::map StringMap; - -//----------------------------------------------------------------------------- -// RenderView messages -// These are messages sent from the browser to the renderer process. - -// these messages belong to "chrome messages" in chromium -// we can add our own class for them but then we need to patch ipc/ipc_message_start.h -// so using same message class for these messages. -// but actual messages are different so they shouldn't mess with chrome messages -#define IPC_MESSAGE_START ChromeMsgStart - -IPC_STRUCT_TRAITS_BEGIN(CacheParamsEfl) - IPC_STRUCT_TRAITS_MEMBER(cache_total_capacity) - IPC_STRUCT_TRAITS_MEMBER(cache_min_dead_capacity) - IPC_STRUCT_TRAITS_MEMBER(cache_max_dead_capacity) -IPC_STRUCT_TRAITS_END() - -IPC_ENUM_TRAITS(tizen_webview::ContentSecurityPolicyType) - -IPC_ENUM_TRAITS(blink::WebNavigationPolicy) -IPC_ENUM_TRAITS(blink::WebNavigationType) - -IPC_STRUCT_TRAITS_BEGIN(NavigationPolicyParams) - IPC_STRUCT_TRAITS_MEMBER(render_view_id) - IPC_STRUCT_TRAITS_MEMBER(cookie) - IPC_STRUCT_TRAITS_MEMBER(url) - IPC_STRUCT_TRAITS_MEMBER(httpMethod) - IPC_STRUCT_TRAITS_MEMBER(referrer) - IPC_STRUCT_TRAITS_MEMBER(policy) - IPC_STRUCT_TRAITS_MEMBER(type) - IPC_STRUCT_TRAITS_MEMBER(should_replace_current_entry) - IPC_STRUCT_TRAITS_MEMBER(is_main_frame) - IPC_STRUCT_TRAITS_MEMBER(is_redirect) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(SelectionColor) - IPC_STRUCT_TRAITS_MEMBER(r) - IPC_STRUCT_TRAITS_MEMBER(g) - IPC_STRUCT_TRAITS_MEMBER(b) - IPC_STRUCT_TRAITS_MEMBER(a) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(SelectionStylePrams) - IPC_STRUCT_TRAITS_MEMBER(underline_state) - IPC_STRUCT_TRAITS_MEMBER(italic_state) - IPC_STRUCT_TRAITS_MEMBER(bold_state) - IPC_STRUCT_TRAITS_MEMBER(bg_color) - IPC_STRUCT_TRAITS_MEMBER(color) - IPC_STRUCT_TRAITS_MEMBER(font_size) - IPC_STRUCT_TRAITS_MEMBER(order_list_state) - IPC_STRUCT_TRAITS_MEMBER(un_order_list_state) - IPC_STRUCT_TRAITS_MEMBER(text_align_center_state) - IPC_STRUCT_TRAITS_MEMBER(text_align_left_state) - IPC_STRUCT_TRAITS_MEMBER(text_align_right_state) - IPC_STRUCT_TRAITS_MEMBER(text_align_full_state) - IPC_STRUCT_TRAITS_MEMBER(has_composition) -IPC_STRUCT_TRAITS_END() - -IPC_ENUM_TRAITS(tizen_webview::Hit_Test_Mode) -IPC_ENUM_TRAITS(tizen_webview::Hit_Test_Result_Context) - -IPC_STRUCT_TRAITS_BEGIN(_Ewk_Hit_Test::Hit_Test_Node_Data) - IPC_STRUCT_TRAITS_MEMBER(tagName) - IPC_STRUCT_TRAITS_MEMBER(nodeValue) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(_Ewk_Hit_Test::Hit_Test_Image_Buffer) - IPC_STRUCT_TRAITS_MEMBER(fileNameExtension) - IPC_STRUCT_TRAITS_MEMBER(imageBitmap) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(_Ewk_Hit_Test) - IPC_STRUCT_TRAITS_MEMBER(context) - IPC_STRUCT_TRAITS_MEMBER(linkURI) - IPC_STRUCT_TRAITS_MEMBER(linkLabel) - IPC_STRUCT_TRAITS_MEMBER(linkTitle) - IPC_STRUCT_TRAITS_MEMBER(imageURI) - IPC_STRUCT_TRAITS_MEMBER(mediaURI) - IPC_STRUCT_TRAITS_MEMBER(isEditable) - IPC_STRUCT_TRAITS_MEMBER(mode) - IPC_STRUCT_TRAITS_MEMBER(nodeData) -// XXX: find a better way to prevent the crash when copying SkBitmap -#if !defined(EWK_BRINGUP) - IPC_STRUCT_TRAITS_MEMBER(imageData) -#endif -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(DidPrintPagesParams) - IPC_STRUCT_TRAITS_MEMBER(metafile_data_handle) - IPC_STRUCT_TRAITS_MEMBER(data_size) - IPC_STRUCT_TRAITS_MEMBER(document_cookie) - IPC_STRUCT_TRAITS_MEMBER(filename) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(tizen_webview::WrtIpcMessageData) - IPC_STRUCT_TRAITS_MEMBER(type) - IPC_STRUCT_TRAITS_MEMBER(value) - IPC_STRUCT_TRAITS_MEMBER(id) - IPC_STRUCT_TRAITS_MEMBER(reference_id) -IPC_STRUCT_TRAITS_END() - -IPC_ENUM_TRAITS(blink::WebViewMode) - -IPC_STRUCT_TRAITS_BEGIN(tizen_webview::Settings) - IPC_STRUCT_TRAITS_MEMBER(javascript_can_open_windows) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(tizen_webview::Error) - IPC_STRUCT_TRAITS_MEMBER(url) - IPC_STRUCT_TRAITS_MEMBER(is_main_frame) - IPC_STRUCT_TRAITS_MEMBER(code) - IPC_STRUCT_TRAITS_MEMBER(description) - IPC_STRUCT_TRAITS_MEMBER(domain) -IPC_STRUCT_TRAITS_END() - - -// Tells the renderer to clear the cache. -IPC_MESSAGE_CONTROL0(EflViewMsg_ClearCache) -IPC_MESSAGE_ROUTED0(EwkViewMsg_UseSettingsFont) -IPC_MESSAGE_ROUTED0(EwkViewMsg_SetBrowserFont) -IPC_MESSAGE_ROUTED0(EwkViewMsg_SuspendScheduledTask) -IPC_MESSAGE_ROUTED0(EwkViewMsg_ResumeScheduledTasks) -IPC_MESSAGE_CONTROL1(EflViewMsg_SetCache, - CacheParamsEfl) - -// Tells the renderer to dump as much memory as it can, perhaps because we -// have memory pressure or the renderer is (or will be) paged out. This -// should only result in purging objects we can recalculate, e.g. caches or -// JS garbage, not in purging irreplaceable objects. -IPC_MESSAGE_CONTROL0(EwkViewMsg_PurgeMemory) - -IPC_MESSAGE_CONTROL4(WrtMsg_SetWidgetInfo, - int, // result: widgetHandle - double, // result: scale - std::string, // result: theme - std::string) // result: encodedBundle - -IPC_MESSAGE_CONTROL2(WrtMsg_ParseUrl, - int, // result: request_id - GURL) // result: url - -IPC_MESSAGE_CONTROL2(WrtMsg_ParseUrlResponse, - int, // result: request_id - GURL) // result: url - -IPC_MESSAGE_CONTROL1(WrtMsg_SendWrtMessage, - tizen_webview::WrtIpcMessageData /* data */); - -IPC_MESSAGE_ROUTED0(EwkViewMsg_GetSelectionStyle) - -IPC_MESSAGE_ROUTED2(EwkViewMsg_SetCSP, - std::string, /* policy */ - tizen_webview::ContentSecurityPolicyType /* header type */) - -IPC_MESSAGE_ROUTED2(EwkViewMsg_SetScroll, - int, /* horizontal position */ - int /* vertical position */) - -IPC_MESSAGE_ROUTED3(EwkViewMsg_DoHitTest, - int, /* horizontal position */ - int, /* vertical position */ - tizen_webview::Hit_Test_Mode /* mode */) - -IPC_MESSAGE_ROUTED1(EwkViewMsg_DidFailLoadWithError, - tizen_webview::Error /* error */) - -IPC_MESSAGE_ROUTED4(EwkViewMsg_DoHitTestAsync, - int, /* horizontal position */ - int, /* vertical position */ - tizen_webview::Hit_Test_Mode, /* mode */ - int64_t /* request id */) - -IPC_MESSAGE_ROUTED3(EwkViewMsg_PrintToPdf, - int, /* width */ - int, /* height */ - base::FilePath /* file name to save pdf*/) - -IPC_MESSAGE_ROUTED1(EflViewMsg_UpdateSettings, tizen_webview::Settings) - -// from renderer to browser - -IPC_MESSAGE_ROUTED1(EwkHostMsg_DidPrintPagesToPdf, - DidPrintPagesParams /* pdf document parameters */) - -IPC_SYNC_MESSAGE_CONTROL1_1(EwkHostMsg_DecideNavigationPolicy, - NavigationPolicyParams, - bool /*handled*/) - -IPC_SYNC_MESSAGE_ROUTED0_2(EwkHostMsg_GetContentSecurityPolicy, - std::string, /* policy */ - tizen_webview::ContentSecurityPolicyType /* header type */) - -IPC_SYNC_MESSAGE_ROUTED1_1(EwkHostMsg_WrtSyncMessage, - tizen_webview::WrtIpcMessageData /* data */, - std::string /*result*/); - -IPC_MESSAGE_ROUTED3(EwkViewMsg_Scale, - double, /* scale factor */ - int, /* center x */ - int /* center y */) - -IPC_MESSAGE_ROUTED1(EwkViewMsg_PlainTextGet, - int /* callback id */) - -IPC_MESSAGE_ROUTED2(EwkHostMsg_PlainTextGetContents, - std::string, /* contentText */ - int /* callback id */) - -IPC_MESSAGE_ROUTED1(EwkHostMsg_WrtMessage, - tizen_webview::WrtIpcMessageData /* data */); - -IPC_MESSAGE_ROUTED2(EwkHostMsg_DidChangeContentsSize, - int, /* width */ - int /* height */) - -IPC_MESSAGE_ROUTED1(EwkViewMsg_SelectionTextStyleState, - SelectionStylePrams /* params */) - -IPC_MESSAGE_ROUTED2(EwkHostMsg_DidChangeMaxScrollOffset, - int, /*max scrollX*/ - int /*max scrollY*/) - -IPC_MESSAGE_ROUTED2(EwkHostMsg_DidChangeScrollOffset, - int, /*scrollX*/ - int /*scrollY*/) - -IPC_MESSAGE_CONTROL3(EwkViewHostMsg_HitTestReply, - int, /* render_view_id */ - _Ewk_Hit_Test, /* Ewk Hit test data without node map */ - NodeAttributesMap /* node attributes */) - -IPC_MESSAGE_CONTROL4(EwkViewHostMsg_HitTestAsyncReply, - int, /* render_view_id */ - _Ewk_Hit_Test, /* Ewk Hit test data without node map */ - NodeAttributesMap, /* node attributes */ - int64_t /* request id */) - -IPC_MESSAGE_ROUTED1(EwkViewMsg_GetMHTMLData, - int /* callback id */) - -IPC_MESSAGE_ROUTED2(EwkHostMsg_ReadMHTMLData, - std::string, /* Mhtml text */ - int /* callback id */) - -IPC_MESSAGE_ROUTED1(EwkHostMsg_DidChangePageScaleFactor, - double /* page scale factor */) - -IPC_MESSAGE_ROUTED2(EwkHostMsg_DidChangePageScaleRange, - double, /* minimum page scale factor */ - double /* maximum page scale factor */) - -IPC_MESSAGE_ROUTED1(EwkViewMsg_SetDrawsTransparentBackground, - bool /* enabled */) - -// Notifies the browser to form submit -IPC_MESSAGE_ROUTED1(EwkHostMsg_FormSubmit, GURL) - -IPC_MESSAGE_ROUTED1(EwkViewMsg_WebAppIconUrlGet, - int /* callback id */) - -IPC_MESSAGE_ROUTED2(EwkHostMsg_WebAppIconUrlGet, - std::string, /* icon url */ - int /* callback id */) - -IPC_MESSAGE_ROUTED1(EwkViewMsg_WebAppIconUrlsGet, - int /* callback id */) - -IPC_MESSAGE_ROUTED2(EwkHostMsg_WebAppIconUrlsGet, - StringMap, /* icon urls */ - int /* callback id */) - -IPC_MESSAGE_ROUTED1(EwkViewMsg_WebAppCapableGet, - int /* calback id */) - -IPC_MESSAGE_ROUTED2(EwkHostMsg_WebAppCapableGet, - bool, /* capable */ - int /* calback id */) - -// Used to set view mode. -IPC_MESSAGE_ROUTED1(ViewMsg_SetViewMode, - blink::WebViewMode /* view_mode */) - -#if defined(TIZEN_MULTIMEDIA_SUPPORT) -// This message runs the GStreamer for decoding audio for webaudio. -IPC_MESSAGE_CONTROL3(EflViewHostMsg_GstWebAudioDecode, - base::SharedMemoryHandle /* encoded_data_handle */, - base::FileDescriptor /* pcm_output */, - uint32_t /* data_size*/) -#endif diff --git a/tizen_src/impl/content/browser/media/media_web_contents_observer_tizen.cc b/tizen_src/impl/content/browser/media/media_web_contents_observer_tizen.cc deleted file mode 100644 index dbc5fdb21a06..000000000000 --- a/tizen_src/impl/content/browser/media/media_web_contents_observer_tizen.cc +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/media/media_web_contents_observer_tizen.h" - -#include "content/browser/media/tizen/browser_media_player_manager_tizen.h" -#include "content/browser/renderer_host/render_process_host_impl.h" -#include "content/common/media/tizen/media_player_messages_tizen.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/browser/web_contents.h" -#include "ipc/ipc_message_macros.h" - -namespace content { - -MediaWebContentsObserverTizen::MediaWebContentsObserverTizen( - RenderViewHost* render_view_host) - : WebContentsObserver(WebContents::FromRenderViewHost(render_view_host)) { -} - -MediaWebContentsObserverTizen::~MediaWebContentsObserverTizen() { -} - -void MediaWebContentsObserverTizen::RenderFrameDeleted( - RenderFrameHost* render_frame_host) { - uintptr_t key = reinterpret_cast(render_frame_host); - media_player_managers_.erase(key); -} - - -bool MediaWebContentsObserverTizen::OnMessageReceived(const IPC::Message& msg, - RenderFrameHost* render_frame_host) { - return OnMediaPlayerMessageReceived(msg, render_frame_host); -} - -bool MediaWebContentsObserverTizen::OnMediaPlayerMessageReceived( - const IPC::Message& msg, - RenderFrameHost* render_frame_host) { - bool handled = true; - - IPC_BEGIN_MESSAGE_MAP(MediaWebContentsObserverTizen, msg) - IPC_MESSAGE_FORWARD(MediaPlayerGstHostMsg_Init, - GetMediaPlayerManager(render_frame_host), - BrowserMediaPlayerManagerTizen::OnInitialize) - - IPC_MESSAGE_FORWARD(MediaPlayerGstHostMsg_DeInit, - GetMediaPlayerManager(render_frame_host), - BrowserMediaPlayerManagerTizen::OnDestroy) - - IPC_MESSAGE_FORWARD(MediaPlayerGstHostMsg_Play, - GetMediaPlayerManager(render_frame_host), - BrowserMediaPlayerManagerTizen::OnPlay) - - IPC_MESSAGE_FORWARD(MediaPlayerGstHostMsg_Pause, - GetMediaPlayerManager(render_frame_host), - BrowserMediaPlayerManagerTizen::OnPause) - - IPC_MESSAGE_FORWARD(MediaPlayerGstHostMsg_SetVolume, - GetMediaPlayerManager(render_frame_host), - BrowserMediaPlayerManagerTizen::OnSetVolume) - - IPC_MESSAGE_FORWARD(MediaPlayerGstHostMsg_SetRate, - GetMediaPlayerManager(render_frame_host), - BrowserMediaPlayerManagerTizen::OnSetRate) - - IPC_MESSAGE_FORWARD(MediaPlayerGstHostMsg_Seek, - GetMediaPlayerManager(render_frame_host), - BrowserMediaPlayerManagerTizen::OnSeek) - - IPC_MESSAGE_UNHANDLED(handled = false) - - IPC_END_MESSAGE_MAP() - return handled; -} - -BrowserMediaPlayerManagerTizen* - MediaWebContentsObserverTizen::GetMediaPlayerManager( - RenderFrameHost* render_frame_host) { - uintptr_t key = reinterpret_cast(render_frame_host); - if (!media_player_managers_.contains(key)) { - media_player_managers_.set( - key, - make_scoped_ptr( - BrowserMediaPlayerManagerTizen::Create(render_frame_host))); - } - return media_player_managers_.get(key); -} - -} // namespace content diff --git a/tizen_src/impl/content/browser/media/media_web_contents_observer_tizen.h b/tizen_src/impl/content/browser/media/media_web_contents_observer_tizen.h deleted file mode 100644 index 928b39ac9e6f..000000000000 --- a/tizen_src/impl/content/browser/media/media_web_contents_observer_tizen.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_MEDIA_MEDIA_WEB_CONTENTS_OBSERVER_TIZEN_H_ -#define CONTENT_BROWSER_MEDIA_MEDIA_WEB_CONTENTS_OBSERVER_TIZEN_H_ - -#include "base/compiler_specific.h" -#include "base/containers/scoped_ptr_hash_map.h" -#include "content/common/content_export.h" -#include "content/public/browser/web_contents_observer.h" - -namespace content { - -class BrowserMediaPlayerManagerTizen; -class RenderViewHost; - -// This class manages all RenderFrame based media related managers at the -// browser side. It receives IPC messages from media RenderFrameObservers and -// forwards them to the corresponding managers. The managers are responsible -// for sending IPCs back to the RenderFrameObservers at the render side. -class CONTENT_EXPORT MediaWebContentsObserverTizen - : public WebContentsObserver { - public: - explicit MediaWebContentsObserverTizen(RenderViewHost* render_view_host); - virtual ~MediaWebContentsObserverTizen(); - - // WebContentsObserver implementations. - virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) override; - virtual bool OnMessageReceived(const IPC::Message& message, - RenderFrameHost* render_frame_host) override; - - // Helper functions to handle media player IPC messages. Returns whether the - // |message| is handled in the function. - bool OnMediaPlayerMessageReceived(const IPC::Message& message, - RenderFrameHost* render_frame_host); - - // Gets the media player manager associated with |render_frame_host|. Creates - // a new one if it doesn't exist. The caller doesn't own the returned pointer. - BrowserMediaPlayerManagerTizen* GetMediaPlayerManager( - RenderFrameHost* render_frame_host); - - private: - // Map from RenderFrameHost* to BrowserMediaPlayerManagerTizen. - typedef base::ScopedPtrHashMap - MediaPlayerManagerMap; - MediaPlayerManagerMap media_player_managers_; - - DISALLOW_COPY_AND_ASSIGN(MediaWebContentsObserverTizen); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_MEDIA_MEDIA_WEB_CONTENTS_OBSERVER_TIZEN_H_ diff --git a/tizen_src/impl/content/browser/media/tizen/browser_demuxer_tizen.cc b/tizen_src/impl/content/browser/media/tizen/browser_demuxer_tizen.cc deleted file mode 100644 index 75cc916bdcd1..000000000000 --- a/tizen_src/impl/content/browser/media/tizen/browser_demuxer_tizen.cc +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/media/tizen/browser_demuxer_tizen.h" -#include "content/common/media/tizen/media_player_messages_tizen.h" - -namespace content { - -class BrowserDemuxerTizen::Internal : public media::DemuxerTizen { - public: - Internal(const scoped_refptr& demuxer, - int demuxer_client_id) - : demuxer_(demuxer), - demuxer_client_id_(demuxer_client_id) { } - - virtual ~Internal() { - DCHECK(ClientIDExists()) << demuxer_client_id_; - demuxer_->RemoveDemuxerClient(demuxer_client_id_); - } - - // media::DemuxerTizen implementation. - virtual void Initialize(media::DemuxerTizenClient* client) override { - DCHECK(!ClientIDExists()) << demuxer_client_id_; - demuxer_->AddDemuxerClient(demuxer_client_id_, client); - } - - virtual void RequestDemuxerConfigs() override { - DCHECK(ClientIDExists()) << demuxer_client_id_; - demuxer_->Send(new MediaPlayerGstMsg_MediaConfigRequest( - demuxer_client_id_)); - } - - virtual void RequestDemuxerData(media::DemuxerStream::Type type) override { - DCHECK(ClientIDExists()) << demuxer_client_id_; - demuxer_->Send(new MediaPlayerGstMsg_ReadFromDemuxer( - demuxer_client_id_, type)); - } - - virtual void RequestDemuxerSeek( - const base::TimeDelta& time_to_seek) override { - DCHECK(ClientIDExists()) << demuxer_client_id_; - demuxer_->Send(new MediaPlayerGstMsg_DemuxerSeekRequest( - demuxer_client_id_, time_to_seek)); - } - - private: - // Helper for DCHECKing that the ID is still registered. - bool ClientIDExists() { - return demuxer_->demuxer_clients_.Lookup(demuxer_client_id_); - } - - scoped_refptr demuxer_; - int demuxer_client_id_; - - DISALLOW_COPY_AND_ASSIGN(Internal); -}; - -BrowserDemuxerTizen::BrowserDemuxerTizen() - : BrowserMessageFilter(MediaPlayerTizenMsgStart) {} - -BrowserDemuxerTizen::~BrowserDemuxerTizen() {} - -void BrowserDemuxerTizen::OverrideThreadForMessage( - const IPC::Message& message, - BrowserThread::ID* thread) { - switch (message.type()) { - case MediaPlayerGstHostMsg_DemuxerReady::ID: - case MediaPlayerGstHostMsg_ReadFromDemuxerAck::ID: - case MediaPlayerGstHostMsg_BufferMetaDataAck::ID: - case MediaPlayerGstHostMsg_DurationChanged::ID: - case MediaPlayerGstHostMsg_DemuxerSeekDone::ID: - *thread = BrowserThread::UI; - return; - } -} - -bool BrowserDemuxerTizen::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(BrowserDemuxerTizen, message) - IPC_MESSAGE_HANDLER(MediaPlayerGstHostMsg_DemuxerReady, OnDemuxerReady) - IPC_MESSAGE_HANDLER(MediaPlayerGstHostMsg_ReadFromDemuxerAck, - OnReadFromDemuxerAck) - IPC_MESSAGE_HANDLER(MediaPlayerGstHostMsg_BufferMetaDataAck, - OnBufferMetaDataAck) - IPC_MESSAGE_HANDLER(MediaPlayerGstHostMsg_DurationChanged, - OnDurationChanged) - IPC_MESSAGE_HANDLER(MediaPlayerGstHostMsg_DemuxerSeekDone, - OnDemuxerSeekDone) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -scoped_ptr BrowserDemuxerTizen::CreateDemuxer( - int demuxer_client_id) { - return scoped_ptr( - new Internal(this, demuxer_client_id)); -} - -void BrowserDemuxerTizen::AddDemuxerClient( - int demuxer_client_id, - media::DemuxerTizenClient* client) { - VLOG(1) << __FUNCTION__ << " peer_pid=" << peer_pid() - << " demuxer_client_id=" << demuxer_client_id; - demuxer_clients_.AddWithID(client, demuxer_client_id); -} - -void BrowserDemuxerTizen::RemoveDemuxerClient(int demuxer_client_id) { - VLOG(1) << __FUNCTION__ << " peer_pid=" << peer_pid() - << " demuxer_client_id=" << demuxer_client_id; - demuxer_clients_.Remove(demuxer_client_id); -} - -void BrowserDemuxerTizen::OnDemuxerReady( - int demuxer_client_id, - const media::DemuxerConfigs& configs) { - media::DemuxerTizenClient* client = - demuxer_clients_.Lookup(demuxer_client_id); - if (client) - client->OnDemuxerConfigsAvailable(configs); -} - -void BrowserDemuxerTizen::OnReadFromDemuxerAck( - int demuxer_client_id, - base::SharedMemoryHandle foreign_memory_handle, - const media::DemuxedBufferMetaData& meta_data) { - media::DemuxerTizenClient* client = - demuxer_clients_.Lookup(demuxer_client_id); - if (client) - client->OnDemuxerDataAvailable(foreign_memory_handle, meta_data); -} - -void BrowserDemuxerTizen::OnBufferMetaDataAck( - int demuxer_client_id, - const media::DemuxedBufferMetaData& meta_data) { - media::DemuxerTizenClient* client = - demuxer_clients_.Lookup(demuxer_client_id); - if (client) - client->OnBufferMetaDataAvailable( meta_data); -} - -void BrowserDemuxerTizen::OnDemuxerSeekDone( - int demuxer_client_id, - const base::TimeDelta& actual_browser_seek_time) { - media::DemuxerTizenClient* client = - demuxer_clients_.Lookup(demuxer_client_id); - if (client) - client->OnDemuxerSeekDone(actual_browser_seek_time); -} - -void BrowserDemuxerTizen::OnDurationChanged( - int demuxer_client_id, - const base::TimeDelta& duration) { - media::DemuxerTizenClient* client = - demuxer_clients_.Lookup(demuxer_client_id); - if (client) - client->OnDemuxerDurationChanged(duration); -} - -} // namespace content diff --git a/tizen_src/impl/content/browser/media/tizen/browser_demuxer_tizen.h b/tizen_src/impl/content/browser/media/tizen/browser_demuxer_tizen.h deleted file mode 100644 index 64cdec367300..000000000000 --- a/tizen_src/impl/content/browser/media/tizen/browser_demuxer_tizen.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_MEDIA_TIZEN_BROWSER_DEMUXER_TIZEN_H_ -#define CONTENT_BROWSER_MEDIA_TIZEN_BROWSER_DEMUXER_TIZEN_H_ - -#include "base/id_map.h" -#include "base/memory/shared_memory.h" -#include "content/public/browser/browser_message_filter.h" -#include "media/base/tizen/demuxer_tizen.h" - -namespace content { - -// Represents the browser process half of an IPC-based demuxer proxy. -// It vends out media::DemuxerTizen instances that are registered with an -// end point in the renderer process. -// -// Refer to RendererDemuxerTizen for the renderer process half. -class CONTENT_EXPORT BrowserDemuxerTizen : public BrowserMessageFilter { - public: - BrowserDemuxerTizen(); - - // BrowserMessageFilter overrides. - virtual void OverrideThreadForMessage( - const IPC::Message& message, - BrowserThread::ID* thread) override; - virtual bool OnMessageReceived(const IPC::Message& message) override; - - // Returns an uninitialized demuxer implementation associated with - // |demuxer_client_id|, which can be used to communicate with the real demuxer - // in the renderer process. - scoped_ptr CreateDemuxer(int demuxer_client_id); - - protected: - friend class base::RefCountedThreadSafe; - virtual ~BrowserDemuxerTizen(); - - private: - class Internal; - - // Called by internal demuxer implementations to add/remove a client - // association. - void AddDemuxerClient( - int demuxer_client_id, - media::DemuxerTizenClient* client); - void RemoveDemuxerClient(int demuxer_client_id); - - // IPC message handlers. - void OnDemuxerReady( - int demuxer_client_id, - const media::DemuxerConfigs& configs); - void OnReadFromDemuxerAck( - int demuxer_client_id, - base::SharedMemoryHandle foreign_memory_handle, - const media::DemuxedBufferMetaData& meta_data); - void OnBufferMetaDataAck( - int demuxer_client_id, - const media::DemuxedBufferMetaData& meta_data); - void OnDemuxerSeekDone( - int demuxer_client_id, - const base::TimeDelta& actual_browser_seek_time); - void OnDurationChanged( - int demuxer_client_id, - const base::TimeDelta& duration); - - IDMap demuxer_clients_; - - DISALLOW_COPY_AND_ASSIGN(BrowserDemuxerTizen); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_MEDIA_TIZEN_BROWSER_DEMUXER_TIZEN_H_ diff --git a/tizen_src/impl/content/browser/media/tizen/browser_media_player_manager_tizen.cc b/tizen_src/impl/content/browser/media/tizen/browser_media_player_manager_tizen.cc deleted file mode 100644 index 6048ba5e0ed4..000000000000 --- a/tizen_src/impl/content/browser/media/tizen/browser_media_player_manager_tizen.cc +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/media/tizen/browser_media_player_manager_tizen.h" - -#include "base/memory/shared_memory.h" -#include "content/browser/media/tizen/browser_demuxer_tizen.h" -#include "content/browser/renderer_host/render_process_host_impl.h" -#include "content/common/media/tizen/media_player_messages_tizen.h" -#include "content/public/browser/web_contents.h" -#include "ipc/ipc_channel_proxy.h" -#include "ipc/ipc_logging.h" -#include "media/base/tizen/media_source_player_gstreamer.h" - -#if defined(TIZEN_CAPI_PLAYER_SUPPORT) && defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -#include "media/base/tizen/media_player_bridge_capi.h" -#else -#include "media/base/tizen/media_player_bridge_gstreamer.h" -#endif - -namespace content { - -BrowserMediaPlayerManagerTizen* BrowserMediaPlayerManagerTizen::Create( - RenderFrameHost* rfh) { - return new BrowserMediaPlayerManagerTizen(rfh); -} - -BrowserMediaPlayerManagerTizen::BrowserMediaPlayerManagerTizen( - RenderFrameHost* render_frame_host) - : render_frame_host_(render_frame_host), - web_contents_(WebContents::FromRenderFrameHost(render_frame_host)), - weak_ptr_factory_(this) { -} - -BrowserMediaPlayerManagerTizen::~BrowserMediaPlayerManagerTizen() { - for (ScopedVector::iterator it = players_.begin(); - it != players_.end(); ++it) { - (*it)->Destroy(); - } - players_.weak_clear(); -} - -media::MediaPlayerTizen* BrowserMediaPlayerManagerTizen::GetPlayer( - int player_id) { - for (ScopedVector::iterator it = players_.begin(); - it != players_.end(); ++it) { - if ((*it)->GetPlayerId() == player_id) - return *it; - } - return NULL; -} - -void BrowserMediaPlayerManagerTizen::OnNewFrameAvailable( - int player_id, - base::SharedMemoryHandle foreign_memory_handle, - uint32 length, base::TimeDelta timestamp) { - Send(new MediaPlayerGstMsg_NewFrameAvailable( - GetRoutingID(), player_id, foreign_memory_handle, length, timestamp)); -} - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -void BrowserMediaPlayerManagerTizen::OnPlatformSurfaceUpdated( - int player_id, - int pixmap_id, - base::TimeDelta timestamp) { - Send(new MediaPlayerGstMsg_PlatformSurfaceUpdated( - GetRoutingID(), player_id, pixmap_id, timestamp)); -} -#endif - -void BrowserMediaPlayerManagerTizen::OnTimeChanged(int player_id) { - Send(new MediaPlayerGstMsg_TimeChanged(GetRoutingID(), player_id)); -} - -void BrowserMediaPlayerManagerTizen::OnPauseStateChange( - int player_id, - bool state) { - Send(new MediaPlayerGstMsg_OnPauseStateChange( - GetRoutingID(), player_id, state)); -} - -void BrowserMediaPlayerManagerTizen::OnSeekStateChange( - int player_id, - bool state) { - Send(new MediaPlayerGstMsg_OnSeekStateChange( - GetRoutingID(), player_id, state)); -} - -void BrowserMediaPlayerManagerTizen::OnRequestSeek( - int player_id, - double seek_time) { - // To handle internal seek. - Send(new MediaPlayerGstMsg_SeekRequest( - GetRoutingID(), player_id, seek_time)); -} - -void BrowserMediaPlayerManagerTizen::OnTimeUpdate( - int player_id, - double current_time) { - Send(new MediaPlayerGstMsg_TimeUpdate( - GetRoutingID(), player_id, current_time)); -} - -void BrowserMediaPlayerManagerTizen::OnBufferUpdate( - int player_id, - std::vector buffer_range) { - Send(new MediaPlayerGstMsg_BufferUpdate( - GetRoutingID(), player_id, buffer_range)); -} - -void BrowserMediaPlayerManagerTizen::OnDurationChange( - int player_id, - double duration) { - Send(new MediaPlayerGstMsg_DurationChanged( - GetRoutingID(), player_id, duration)); -} - -void BrowserMediaPlayerManagerTizen::OnReadyStateChange( - int player_id, - media::MediaPlayerTizen::ReadyState state) { - Send(new MediaPlayerGstMsg_ReadyStateChange( - GetRoutingID(), player_id, state)); -} - -void BrowserMediaPlayerManagerTizen::OnNetworkStateChange( - int player_id, - media::MediaPlayerTizen::NetworkState state) { - Send(new MediaPlayerGstMsg_NetworkStateChange( - GetRoutingID(), player_id, state)); -} - -void BrowserMediaPlayerManagerTizen::OnMediaDataChange( - int player_id, - int format, - int height, - int width, - int media) { - Send(new MediaPlayerGstMsg_MediaDataChanged( - GetRoutingID(), player_id, format, height, width, media)); -} - -int BrowserMediaPlayerManagerTizen::GetRoutingID() { - if (!render_frame_host_) - return 0; - return render_frame_host_->GetRoutingID(); -} - -bool BrowserMediaPlayerManagerTizen::Send(IPC::Message* msg) { - if (!render_frame_host_) - return false; - return render_frame_host_->Send(msg); -} - -void BrowserMediaPlayerManagerTizen::OnInitialize( - int player_id, - MediaPlayerHostMsg_Initialize_Type type, - const GURL& url, - double volume, - int demuxer_client_id) { - RemovePlayer(player_id); - - if (type == MEDIA_PLAYER_TYPE_URL) { - -#if defined(TIZEN_CAPI_PLAYER_SUPPORT) && defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - LOG(INFO) << "MediaElement is using |CAPI| to play media"; - AddPlayer(new media::MediaPlayerBridgeCapi(player_id, url, volume, this)); -#else - LOG(INFO) << "MediaElement is using |Gstreamer| to play media"; - AddPlayer( - new media::MediaPlayerBridgeGstreamer(player_id, url, volume, this)); -#endif - - } else if (type == MEDIA_PLAYER_TYPE_MEDIA_SOURCE) { - RenderProcessHostImpl* host = static_cast( - web_contents()->GetRenderProcessHost()); - AddPlayer(new media::MediaSourcePlayerGstreamer( - player_id, - host->browser_demuxer_tizen()->CreateDemuxer(demuxer_client_id), - this)); - } else { - LOG(ERROR) << __FUNCTION__ << " Load type is wrong!"; - } -} - -void BrowserMediaPlayerManagerTizen::OnDestroy(int player_id) { - VLOG(1) << __FUNCTION__ << " " << player_id; - RemovePlayer(player_id); -} - -void BrowserMediaPlayerManagerTizen::OnPlay(int player_id) { - media::MediaPlayerTizen* player = GetPlayer(player_id); - if (player) - player->Play(); -} - -void BrowserMediaPlayerManagerTizen::OnPause(int player_id) { - media::MediaPlayerTizen* player = GetPlayer(player_id); - if (player) - player->Pause(false); -} - -void BrowserMediaPlayerManagerTizen::OnSetVolume( - int player_id, - double volume) { - media::MediaPlayerTizen* player = GetPlayer(player_id); - if (player) - player->SetVolume(volume); -} - -void BrowserMediaPlayerManagerTizen::OnSetRate(int player_id, double rate) { - media::MediaPlayerTizen* player = GetPlayer(player_id); - if (player) - player->SetRate(rate); -} - -void BrowserMediaPlayerManagerTizen::OnSeek(int player_id, double time) { - media::MediaPlayerTizen* player = GetPlayer(player_id); - if (player) - player->Seek(time); -} - -void BrowserMediaPlayerManagerTizen::AddPlayer( - media::MediaPlayerTizen* player) { - DCHECK(!GetPlayer(player->GetPlayerId())); - VLOG(1) << "BrowserMediaPlayerManagerTizen::" << __FUNCTION__ - << " Player-Id : " << player->GetPlayerId(); - players_.push_back(player); -} - -void BrowserMediaPlayerManagerTizen::RemovePlayer(int player_id) { - for (ScopedVector::iterator it = players_.begin(); - it != players_.end(); ++it) { - media::MediaPlayerTizen* player = *it; - if (player->GetPlayerId() == player_id) { - VLOG(1) << "BrowserMediaPlayerManagerTizen::" << __FUNCTION__ - << " Player-Id : " << player->GetPlayerId(); - players_.weak_erase(it); - player->Destroy(); - break; - } - } -} - -} // namespace content - diff --git a/tizen_src/impl/content/browser/media/tizen/browser_media_player_manager_tizen.h b/tizen_src/impl/content/browser/media/tizen/browser_media_player_manager_tizen.h deleted file mode 100644 index 2456cf8a4a9f..000000000000 --- a/tizen_src/impl/content/browser/media/tizen/browser_media_player_manager_tizen.h +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_MEDIA_TIZEN_BROWSER_MEDIA_PLAYER_MANAGER_TIZEN_H_ -#define CONTENT_BROWSER_MEDIA_TIZEN_BROWSER_MEDIA_PLAYER_MANAGER_TIZEN_H_ - -#include "base/memory/scoped_vector.h" -#include "content/public/browser/browser_message_filter.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/browser/web_contents_observer.h" -#include "media/base/tizen/media_player_manager_tizen.h" - -namespace content { - -// This class manages all the MediaPlayerTizen objects. It receives -// control operations from the the render process, and forwards -// them to corresponding MediaPlayerTizen object. Callbacks from -// MediaPlayerTizen objects are converted to IPCs and then sent to the -// render process. -class CONTENT_EXPORT BrowserMediaPlayerManagerTizen - : public media::MediaPlayerManager { - public: - // Returns a new instance using the registered factory if available. - static BrowserMediaPlayerManagerTizen* Create( RenderFrameHost* efh); - virtual ~BrowserMediaPlayerManagerTizen(); - - // media::MediaPlayerManager implementation. - virtual media::MediaPlayerTizen* GetPlayer(int player_id) override; - virtual void OnTimeChanged(int player_id) override; - virtual void OnTimeUpdate(int player_id, double current_time) override; - virtual void OnPauseStateChange(int player_id, bool state) override; - virtual void OnSeekStateChange(int player_id, bool state) override; - virtual void OnRequestSeek(int player_id, double seek_time) override; - virtual void OnBufferUpdate( - int player_id, - std::vector buffer_range) override; - virtual void OnDurationChange(int player_id, double duration) override; - virtual void OnReadyStateChange( - int player_id, - media::MediaPlayerTizen::ReadyState state) override; - virtual void OnNetworkStateChange( - int player_id, - media::MediaPlayerTizen::NetworkState state) override; - virtual void OnMediaDataChange( - int player_id, - int format, - int height, - int width, - int media) override; - virtual void OnNewFrameAvailable( - int player_id, - base::SharedMemoryHandle foreign_memory_handle, - uint32 length, base::TimeDelta timestamp) override; - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - virtual void OnPlatformSurfaceUpdated( - int player_id, - int pixmap_id, - base::TimeDelta timestamp) override; -#endif - - // Helper function to handle IPC from RenderMediaPlayerMangaerTizen. - virtual void OnPlay(int player_id); - virtual void OnPause(int player_id); - virtual void OnSetVolume(int player_id, double volume); - virtual void OnSetRate(int player_id, double rate); - virtual void OnInitialize( - int player_id, - MediaPlayerHostMsg_Initialize_Type type, - const GURL& url, - double volume, - int demuxer_client_id); - virtual void OnDestroy(int player_id); - virtual void OnSeek(int player_id, double time); - - protected: - // Clients must use Create() or subclass constructor. - explicit BrowserMediaPlayerManagerTizen(RenderFrameHost* render_frame_host); - - void AddPlayer(media::MediaPlayerTizen* player); - void RemovePlayer(int player_id); - - // Helper function to send messages to RenderFrameObserver. - bool Send(IPC::Message* msg); - - int GetRoutingID(); - WebContents* web_contents() const { return web_contents_; } - - private: - // An array of managed players. - ScopedVector players_; - RenderFrameHost* render_frame_host_; - WebContents* const web_contents_; - base::WeakPtrFactory weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(BrowserMediaPlayerManagerTizen); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_MEDIA_TIZEN_BROWSER_MEDIA_PLAYER_MANAGER_TIZEN_H_ diff --git a/tizen_src/impl/content/browser/media/tizen/webaudio_decoder_browser_gstreamer.cc b/tizen_src/impl/content/browser/media/tizen/webaudio_decoder_browser_gstreamer.cc deleted file mode 100644 index 5bb192cc1b16..000000000000 --- a/tizen_src/impl/content/browser/media/tizen/webaudio_decoder_browser_gstreamer.cc +++ /dev/null @@ -1,483 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/media/tizen/webaudio_decoder_browser_gstreamer.h" - -#include "base/bind.h" -#include "base/strings/string_util.h" -#include "base/time/time.h" -#include "gst/app/gstappsink.h" -#include "gst/audio/audio.h" -#include "media/base/audio_bus.h" -#include "media/base/limits.h" -#include "media/base/tizen/webaudio_media_codec_info_tizen.h" -#include "third_party/WebKit/public/platform/WebAudioBus.h" - -namespace content { - -#define CHUNK_SIZE 204800 // (4096*50) - -static int gst_dec_count_ = 32; - -#if GST_VERSION_MAJOR == 1 -static int audio_width_ = 16; -const char* kdecodebin = "decodebin"; -#endif - -//////////////////////////////////////// -// GSTDecoder class - declaration -class GSTDecoder { - public: - void InitializeGstDestination(int pcm_output, - uint16_t number_of_channels, - uint32_t sample_rate, - size_t number_of_frames); - void SendGstOutputUsinghandle(int pcm_output, uint8_t* buffer, int buf_size); - static void MediaFileDecoder(GstAppData* appData); - - // callbacks - static void cb_newpad (GstElement* decodebin, GstPad* pad, GstAppData* data); - static void cb_need_data (GstElement* source, guint size, GstAppData* data); - static void cb_eos (GstAppSink* sink, gpointer user_data); - static GstFlowReturn cb_new_preroll (GstAppSink* sink, gpointer user_data); - static GstFlowReturn cb_new_buffer (GstAppSink* sink, gpointer user_data); - static GstBusSyncReply cb_pipeline_message (GstBus* bus, - GstMessage* message, - GstAppData* data); -}; // GSTDecoder class - -void GSTDecoder::InitializeGstDestination(int pcm_output, - uint16_t number_of_channels, - uint32_t sample_rate, - size_t number_of_frames) { - struct media::WebAudioMediaCodecInfoTizen info = { - static_cast(number_of_channels), - static_cast(sample_rate), - static_cast(number_of_frames) - }; - - HANDLE_EINTR(write(pcm_output, &info, sizeof(info))); -} - -void GSTDecoder::SendGstOutputUsinghandle(int pcm_output, uint8_t * buffer, int buf_size) { - size_t count = buf_size; - ssize_t total_bytes = 0; - while (count > 0) { - int bytes_to_write = (count >= PIPE_BUF) ? PIPE_BUF : count; - ssize_t bytes_written = HANDLE_EINTR(write(pcm_output, buffer, bytes_to_write)); - if (bytes_written == -1) - break; - count -= bytes_written; - buffer += bytes_written; - total_bytes += bytes_written; - } - return; -} - -void GSTDecoder::MediaFileDecoder(GstAppData* appData) { - if(!appData) - return; - - if (!gst_is_initialized()) { - GError* err = NULL; - if (!gst_init_check(NULL, NULL, &err)) { - LOG(ERROR) << "Gst could not be initialized"; - close(appData->pcm_output_); - return; - } - } - - // makes gst-element(s) - appData->app_src_ = gst_element_factory_make("appsrc", NULL); - appData->app_sink_ = gst_element_factory_make("appsink", NULL); -#if GST_VERSION_MAJOR == 1 - appData->decoder_ = gst_element_factory_make(kdecodebin, NULL); -#else - appData->decoder_ = gst_element_factory_make("decodebin2", NULL); -#endif - appData->convert_ = gst_element_factory_make("audioconvert", NULL); - - appData->resample_ = gst_element_factory_make ("audioresample", NULL); - appData->capsfilter_ = gst_element_factory_make("capsfilter", NULL); -#if GST_VERSION_MAJOR == 1 - appData->caps_ = gst_caps_new_simple("audio/x-raw", "format", G_TYPE_STRING, - "S16LE", "rate", G_TYPE_INT, 44100, - "channels", G_TYPE_INT, 2, "layout", - G_TYPE_STRING, "interleaved", NULL); -#else - appData->caps_ = gst_caps_new_simple("audio/x-raw-int", "width", G_TYPE_INT, 16, NULL); -#endif - - if (!appData->app_src_ || !appData->app_sink_ || !appData->decoder_ || - !appData->convert_ || !appData->resample_ || !appData->capsfilter_ || - !appData->caps_) { - LOG(ERROR) << "Creation of one or more gst-element(s) for decoder pipeline failed"; - return; - } - - g_object_set(G_OBJECT(appData->capsfilter_), "caps", appData->caps_, NULL); - gst_caps_unref(appData->caps_); - - // sets propeties for element(s) - g_object_set(G_OBJECT(appData->app_sink_), "sync", FALSE, NULL); - - // connects signal(s) to element(s) - g_signal_connect(appData->app_src_, "need-data", G_CALLBACK(cb_need_data), appData); - g_signal_connect(appData->decoder_, "pad-added", G_CALLBACK(cb_newpad), appData); - -#if GST_VERSION_MAJOR == 1 - GstAppSinkCallbacks callbacks = { cb_eos, cb_new_preroll, - cb_new_buffer}; -#else - GstAppSinkCallbacks callbacks = { cb_eos, cb_new_preroll, - cb_new_buffer, NULL, - { NULL, NULL, NULL } }; -#endif - gst_app_sink_set_callbacks(GST_APP_SINK(appData->app_sink_), &callbacks, appData, NULL); - - //FIXME: gst-element(s) can have 94 each name, but this can not be enough - gchar pipeline_name[16] = {0,}; - sprintf(pipeline_name, "pipeln_%d", gst_dec_count_); - - memset(appData->audioout_name_, 0, 16); - sprintf(appData->audioout_name_, "audout_%d", gst_dec_count_); - - gst_dec_count_++; - if (gst_dec_count_ > 126) - gst_dec_count_ = 32; - - // makes gst-pipeline - appData->pipeline_ = gst_pipeline_new((const gchar*)&pipeline_name); - gst_bin_add_many(GST_BIN(appData->pipeline_), appData->app_src_, appData->decoder_, NULL); - if (!gst_element_link(appData->app_src_, appData->decoder_)) { - LOG(ERROR) << __FUNCTION__ << " Something wrong on gst initialization"; - if ( appData->pipeline_ ) - gst_object_unref(appData->pipeline_); - return; - } - - // makes audio-output and links it to gst-pipeline - appData->audioout_ = gst_bin_new(appData->audioout_name_); - appData->audiopad_ = gst_element_get_static_pad(appData->convert_, "sink"); - - gst_bin_add_many(GST_BIN(appData->audioout_), appData->convert_, - appData->resample_, appData->capsfilter_, appData->app_sink_, NULL); - if (!gst_element_link_many(appData->convert_, appData->resample_, - appData->capsfilter_, appData->app_sink_, NULL)) { - LOG(ERROR) << __FUNCTION__ << "Some element could not be linked"; - if ( appData->pipeline_ ) - gst_object_unref(appData->pipeline_); - return; - } - - gst_element_add_pad(appData->audioout_, gst_ghost_pad_new("sink", appData->audiopad_)); - gst_object_unref(appData->audiopad_); - gst_bin_add(GST_BIN(appData->pipeline_), appData->audioout_); - - GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(appData->pipeline_)); - if (!bus) { - LOG(ERROR) << __FUNCTION__ << "GStreamer bus creation failed"; - if ( appData->pipeline_ ) - gst_object_unref(appData->pipeline_); - return; - } -#if GST_VERSION_MAJOR == 1 - gst_bus_set_sync_handler(bus, (GstBusSyncHandler)cb_pipeline_message, appData, - NULL); -#else - gst_bus_set_sync_handler(bus, (GstBusSyncHandler)cb_pipeline_message, appData); -#endif - - // actually works decoding - gst_element_set_state(appData->pipeline_, GST_STATE_PLAYING); - - //FIXME: Check if its possible to remove usleep() and make any gst - //async call so that GST wont block on Browser UI thread. - while (appData->isRunning_) { - usleep(10); - } - - // returns resource(s) - g_signal_handlers_disconnect_by_func( - bus, reinterpret_cast(cb_pipeline_message), appData); -#if GST_VERSION_MAJOR == 1 - gst_bus_set_sync_handler(bus, NULL, NULL, NULL); -#else - gst_bus_set_sync_handler(bus, NULL, NULL); -#endif - gst_object_unref(bus); - gst_element_set_state(appData->pipeline_, GST_STATE_NULL); - gst_object_unref(appData->pipeline_); -} - -void GSTDecoder::cb_newpad(GstElement* decodebin, GstPad* pad, GstAppData* data) { -#if GST_VERSION_MAJOR == 1 - GstPad* sink_pad = gst_element_get_static_pad(data->audioout_, "sink"); -#else - GstPad* sink_pad = gst_element_get_pad(data->audioout_, "sink"); -#endif - if (GST_PAD_IS_LINKED(sink_pad)) { - g_object_unref(sink_pad); - return; - } - - GstCaps* caps = NULL; - GstStructure* str = NULL; - -#if GST_VERSION_MAJOR == 1 - caps = gst_pad_query_caps(pad, NULL); -#else - caps = gst_pad_get_caps(pad); -#endif - if (caps) { - str = gst_caps_get_structure(caps, 0); - if (str) { - if (!g_strrstr(gst_structure_get_name(str), data->audioout_name_)) - gst_pad_link(pad, sink_pad); - } - } - g_object_unref(sink_pad); - gst_caps_unref(caps); -} - -void GSTDecoder::cb_need_data (GstElement* source, guint size, GstAppData* data) { - if (data->isEndOfStream_) - return; - - guint len = CHUNK_SIZE; - if ((data->enc_offset_ + len ) > data->enc_length_) - len = data->enc_length_ - data->enc_offset_; - -#if GST_VERSION_MAJOR == 1 - GstBuffer* buffer = gst_buffer_new_wrapped_full(GST_MEMORY_FLAG_READONLY, - data->encodeddata_ + data->enc_offset_, - len, 0, len, NULL, NULL); - if (!buffer) - { - LOG(ERROR) << __FUNCTION__ << "cb_need_data: buffer creation: FAILED"; - return; - } -#else - GstBuffer* buffer = gst_buffer_new(); - if (!buffer) - return; - - GST_BUFFER_DATA(buffer) = data->encodeddata_ + data->enc_offset_; - GST_BUFFER_SIZE(buffer) = len; -#endif - data->enc_offset_ += len; - - GstFlowReturn ret = GST_FLOW_OK; - g_signal_emit_by_name(data->app_src_, "push-buffer", buffer, &ret); - - if (ret != GST_FLOW_OK) { - LOG(ERROR) << "cb_need_data: push-buffer ret: FAILED"; - data->isRunning_ = false; - } - - if (data->enc_offset_ >= data->enc_length_) { - data->isEndOfStream_ = TRUE; - g_signal_emit_by_name(data->app_src_, "end-of-stream", &ret); - } - - gst_buffer_unref(buffer); -} - -void GSTDecoder::cb_eos (GstAppSink* sink, gpointer user_data) { - GstAppData* data = reinterpret_cast(user_data); - if (!data->isEndOfStream_) { - LOG(ERROR) << "not end of stream yet appsrc-side"; - } - - close(data->pcm_output_); - data->isRunning_ = false; -} - -GstFlowReturn GSTDecoder::cb_new_preroll (GstAppSink* sink, gpointer user_data) { - return GST_FLOW_OK; -} - -GstFlowReturn GSTDecoder::cb_new_buffer (GstAppSink* sink, gpointer user_data) { -#if GST_VERSION_MAJOR == 1 - GstSample* sample = gst_app_sink_pull_sample(sink); - GstBuffer* buffer = gst_sample_get_buffer(sample); -#else - GstBuffer* buffer = gst_app_sink_pull_buffer(GST_APP_SINK(sink)); -#endif - - if (!buffer) - return GST_FLOW_ERROR; - - GstAppData* data = (GstAppData*) (user_data); - - if (data->isNewRequest_) { - GstCaps* caps = NULL; - GstStructure* str = NULL; -#if GST_VERSION_MAJOR == 1 - caps = gst_sample_get_caps(sample); -#else - caps = gst_buffer_get_caps(buffer); -#endif - if (caps) - str = gst_caps_get_structure(caps, 0); - - gboolean ret = true; - gint channel = 0; - gint rate = 0; - gint width = 0; - if (caps && str) { - ret &= gst_structure_get_int(str, "channels", &channel); - ret &= gst_structure_get_int(str, "rate", &rate); -#if !(GST_VERSION_MAJOR == 1) - ret &= gst_structure_get_int(str, "width", &width); -#endif - } - -#if GST_VERSION_MAJOR == 1 - if (!caps || !str || !ret || !channel || !rate) { -#else - if (!caps || !str || !ret || !channel || !rate || !width) { -#endif - gst_caps_unref(caps); - gst_buffer_unref(buffer); - return GST_FLOW_ERROR; - } - -#if GST_VERSION_MAJOR == 1 - GstClockTime duration = (static_cast (gst_buffer_get_size(buffer)) - * 8 * GST_SECOND) / (channel * rate * audio_width_); -#else - GstClockTime duration = (static_cast (GST_BUFFER_SIZE(buffer))*8*GST_SECOND) - / (channel*rate*width); -#endif - int frames = GST_CLOCK_TIME_TO_FRAMES(duration, rate); - - data->gst_decoder_->InitializeGstDestination(data->pcm_output_, channel, rate, frames); - data->isNewRequest_ = false; - } - -#if GST_VERSION_MAJOR == 1 - GstMapInfo gst_map; - gst_buffer_map(buffer, &gst_map, (GstMapFlags)(GST_MAP_READ)); - if (buffer && gst_map.size > 0) { - data->gst_decoder_->SendGstOutputUsinghandle(data->pcm_output_, - gst_map.data, - gst_map.size); - gst_buffer_unmap(buffer, &gst_map); -#else - if (buffer && buffer->size > 0) { - data->gst_decoder_->SendGstOutputUsinghandle(data->pcm_output_, - buffer->data, - buffer->size); -#endif - } - - gst_buffer_unref(buffer); - return GST_FLOW_OK; -} - -GstBusSyncReply GSTDecoder::cb_pipeline_message(GstBus* bus, - GstMessage* message, - GstAppData* data) { - switch (GST_MESSAGE_TYPE(message)) { - case GST_MESSAGE_ERROR: - GError* error; - gst_message_parse_error(message, &error, NULL); - LOG(ERROR) << "Error message : " << error->message - << " recieved from : "<< GST_MESSAGE_SRC_NAME(message) - << ", error code : " << error->code; - g_error_free(error); - - if (data->isRunning_) { - close(data->pcm_output_); - data->isRunning_ = false; - } - break; - default: - LOG(WARNING) << "Unhandled GStreamer message type : " - << GST_MESSAGE_TYPE_NAME(message); - break; - } - - gst_message_unref(message); - - return GST_BUS_DROP; -} - -//////////////////////////////////////// -// BrowserMessageFilterTizen class - -// static -BrowserMessageFilterTizen* BrowserMessageFilterTizen::GetInstance() { - return Singleton::get(); -} - -BrowserMessageFilterTizen::BrowserMessageFilterTizen() - : gst_thread_("GstThread") { -} - -BrowserMessageFilterTizen::~BrowserMessageFilterTizen() { -} - -void BrowserMessageFilterTizen::DecodeUsingGST( - base::SharedMemoryHandle foreign_memory_handle, - base::FileDescriptor pcm_output, - uint32_t data_size) { - - base::SharedMemory shared_memory(foreign_memory_handle, false); - shared_memory.Map(data_size); - - GstAppData* data = new GstAppData; - if (!data) - return; - - memset(data, 0, sizeof(GstAppData)); - - data->encodeddata_ = (uint8_t*) (malloc(data_size)); - if (!data->encodeddata_) { - LOG(ERROR) << "BrowserMessageFilterTizen::"<<__FUNCTION__ - << " - encodeddata malloc failed"; - delete data; - return; - } - memcpy(data->encodeddata_, static_cast(shared_memory.memory()), data_size); - - data->isRunning_ = true; - data->enc_length_ = data_size; - data->pcm_output_ = pcm_output.fd; - data->isEndOfStream_ = false; - data->isNewRequest_ = true; - - GSTDecoder *decoder = new GSTDecoder(); - if (decoder) { - data->gst_decoder_ = decoder; - decoder->MediaFileDecoder(data); - delete decoder; - } - - if (data->encodeddata_) { - free(data->encodeddata_); - data->encodeddata_ = NULL; - } - delete data; -} - -void BrowserMessageFilterTizen::EncodedDataReceived( - base::SharedMemoryHandle foreign_memory_handle, - base::FileDescriptor pcm_output, - uint32_t data_size) { - - if (!gst_thread_.IsRunning() && !gst_thread_.Start()) { - LOG(ERROR) << "BrowserMessageFilterTizen::"<<__FUNCTION__ - << " - Starting GStreamer thread failed"; - return; - } - - gst_thread_.message_loop()->PostTask(FROM_HERE, - base::Bind(&BrowserMessageFilterTizen::DecodeUsingGST, - base::Unretained(this), foreign_memory_handle, - pcm_output, data_size)); -} - -} // namespace content diff --git a/tizen_src/impl/content/browser/media/tizen/webaudio_decoder_browser_gstreamer.h b/tizen_src/impl/content/browser/media/tizen/webaudio_decoder_browser_gstreamer.h deleted file mode 100644 index 22d29e85f2cb..000000000000 --- a/tizen_src/impl/content/browser/media/tizen/webaudio_decoder_browser_gstreamer.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_MEDIA_TIZEN_WEBAUDIO_DECODER_BROWSER_GSTREAMER_H_ -#define CONTENT_BROWSER_MEDIA_TIZEN_WEBAUDIO_DECODER_BROWSER_GSTREAMER_H_ - -#include "base/basictypes.h" -#include "base/memory/singleton.h" -#include "base/memory/shared_memory.h" -#include "base/threading/thread.h" -#include "content/common/content_export.h" -#include -#include - -namespace content { - -class GSTDecoder; - -// GstAppData struct -typedef struct _GstAppData { - GstElement *pipeline_; - GstElement *app_src_, *app_sink_; - GstElement *decoder_, *convert_, *resample_, *capsfilter_; - GstCaps *caps_; - GstElement *audioout_; - GstElement *audio_; - GstPad *audiopad_; - - gchar audioout_name_[16]; - - bool isRunning_; - - guint sourceid_; // To control the GSource - guint8 *encodeddata_; - gsize enc_length_; - guint64 enc_offset_; - - int pcm_output_; - bool isEndOfStream_; - bool isNewRequest_; - - GSTDecoder *gst_decoder_; -} GstAppData; - -// BrowserMessageFilterTizen class -class CONTENT_EXPORT BrowserMessageFilterTizen { - public: - static BrowserMessageFilterTizen* GetInstance(); - - void EncodedDataReceived(base::SharedMemoryHandle foreign_memory_handle, - base::FileDescriptor pcm_output, - uint32_t data_size); - - private: - friend struct DefaultSingletonTraits; - BrowserMessageFilterTizen(); - virtual ~BrowserMessageFilterTizen(); - void DecodeUsingGST(base::SharedMemoryHandle foreign_memory_handle, - base::FileDescriptor pcm_output, - uint32_t data_size); - - base::Thread gst_thread_; - - DISALLOW_COPY_AND_ASSIGN(BrowserMessageFilterTizen); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_MEDIA_TIZEN_WEBAUDIO_DECODER_BROWSER_GSTREAMER_H_ diff --git a/tizen_src/impl/content/common/gpu/media/tizen/tizen_video_decode_accelerator.cc b/tizen_src/impl/content/common/gpu/media/tizen/tizen_video_decode_accelerator.cc deleted file mode 100644 index d79e7e65aba8..000000000000 --- a/tizen_src/impl/content/common/gpu/media/tizen/tizen_video_decode_accelerator.cc +++ /dev/null @@ -1,930 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/common/gpu/media/tizen/tizen_video_decode_accelerator.h" - -#include -#include -#include -#include -#include - -#include "base/bind.h" -#include "base/memory/shared_memory.h" -#include "base/message_loop/message_loop_proxy.h" -#include "base/synchronization/waitable_event.h" -#include "base/time/time.h" -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -#include "ui/gl/efl_pixmap.h" -#else -#include "base/process/process.h" -#endif - -#if GST_VERSION_MAJOR == 1 -#include -#else -#include -#endif - -using media::VideoFrame; - -namespace { - -struct GstElementDeleter { - void operator()(GstElement* ptr) const { - DCHECK(ptr != NULL); - gst_object_unref(ptr); - } -}; - -// Gstreamer elements and names. -const char* kDecoderName = "decoder"; -#if GST_VERSION_MAJOR == 1 -const char* kDecoderGstElement = "omxh264dec"; -#else -const char* kDecoderGstElement = "omx_h264dec"; -#endif - -// Generating Unique Key from given width and height. -int32 ConvertWidthAndHeightToKey(int width, int height) { - return ((width << 16) | height); -} -} // namespace - -namespace content { - -enum { - MAX_BITRATE = 2000000, // bps. - INPUT_BUFFER_SIZE = MAX_BITRATE / 8, // bytes. 1 sec for H.264 HD video. - ID_LAST = 0x3FFFFFFF, // wrap round ID after this -}; - -media::VideoDecodeAccelerator* CreateTizenVideoDecodeAccelerator() { - return new TizenVideoDecodeAccelerator(); -} - -struct TizenVideoDecodeAccelerator::BitstreamBufferRef { - BitstreamBufferRef( - base::WeakPtr client, - const scoped_refptr& client_message_loop_proxy, - base::SharedMemory* shm, - size_t size, - int32 input_id) - : client_(client), - client_message_loop_proxy_(client_message_loop_proxy), - shm_(shm), - size_(size), - bytes_used_(0), - input_id_(input_id), - gst_buffer_(NULL) {} - - ~BitstreamBufferRef() { - if (input_id_ >= 0) { - client_message_loop_proxy_->PostTask( - FROM_HERE, - base::Bind( - &media::VideoDecodeAccelerator::Client::NotifyEndOfBitstreamBuffer, - client_, - input_id_)); - } - } - - static void Destruct(gpointer data) { - DCHECK(data != NULL); - BitstreamBufferRef* pRef = static_cast(data); - delete pRef; - } - - base::WeakPtr client_; - scoped_refptr client_message_loop_proxy_; - scoped_ptr shm_; - size_t size_; - off_t bytes_used_; - int32 input_id_; - GstBuffer* gst_buffer_; -}; - -struct TizenVideoDecodeAccelerator::Impl { - Impl() - : can_feed_(true), - is_destroying_(false), - pipeline_(NULL), - sink_(NULL), - appsrc_(NULL), - io_message_loop_proxy_(base::MessageLoopProxy::current()), - bitstream_buffer_id_(0), - gst_thread_("TizenDecoderThreadGst") -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - ,pixmap_id_(0), - gst_width_(0), - gst_height_(0), - damage_(0), - damage_handler_(NULL), - is_x_window_handle_set_(false) -#else - ,caps_width_(0), - caps_height_(0) -#endif -{ -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - xpixmap_buffer_map_.clear(); -#endif -} - -#if !defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - static GstFlowReturn OnDecoded(GstAppSink* sink, gpointer app_data); - void DeliverVideoFrame(GstBuffer* buffer, - int32 bitstream_buffer_id, - gfx::Rect frame_size); - void CreateAppSinkElement(); - static void OnSinkCapChanged( - GstPad* sink_pad, GParamSpec* gparamspec, void* user_data); -#endif - - static GstBusSyncReply OnBusMessage( - GstBus* bus, GstMessage* msg, gpointer data) { - switch (GST_MESSAGE_TYPE(msg)) { - case GST_MESSAGE_ERROR: { - gchar* debug = NULL; - GError* error = NULL; - gst_message_parse_error(msg, &error, &debug); - LOG(ERROR) << __FUNCTION__ - << " GSTError happens from bus at " - << GST_OBJECT_NAME(msg->src) - << ":" << error->message; - LOG(ERROR) << __FUNCTION__ - << " Debugging Info: " - << (debug != NULL ? debug : "none"); - g_error_free(error); - g_free(debug); - break; - } -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - case GST_MESSAGE_ELEMENT: { - TizenVideoDecodeAccelerator::Impl* obj_impl = - static_cast(data); - if (obj_impl) { - if (obj_impl->IsXWindowHandleSet()) { -#if GST_VERSION_MAJOR == 1 - if (gst_is_video_overlay_prepare_window_handle_message(msg)) { -#else - if (gst_structure_has_name(msg->structure, "prepare-xid")) { -#endif - obj_impl->OnXWindowIdPrepared(msg); - gst_message_unref(msg); - return GST_BUS_PASS; - } - } - } else { - LOG(ERROR) << __FUNCTION__ << "Accelerator is NULL"; - } - break; - } -#endif - default: - break; - } - return GST_BUS_PASS; - } - - static void StartFeed(GstAppSrc *source, guint size, gpointer app) { - DCHECK(source); - content::TizenVideoDecodeAccelerator::Impl* impl = - static_cast(app); - impl->can_feed_ = true; - } - - static void StopFeed(GstAppSrc *source, gpointer app) { - DCHECK(source); - content::TizenVideoDecodeAccelerator::Impl* impl = - static_cast(app); - impl->can_feed_ = false; - } - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - bool IsXWindowHandleSet() const {return is_x_window_handle_set_;} - void OnXWindowIdPrepared(GstMessage* message); - void SetXWindowHandle(bool handle_set); - void SetPixmap(const int32& gst_width, const int32& gst_height); - void DeregisterDamageHandler(); - static Eina_Bool OnSurfaceChanged(void* ptr_acc, int type, void* event); - static void OnSinkCapChanged( - GstPad* sink_pad, GParamSpec* gparamspec, void* user_data); -#endif - - volatile bool can_feed_; - volatile bool is_destroying_; - GstElement* pipeline_; - GstElement* sink_; - GstElement* appsrc_; - scoped_refptr io_message_loop_proxy_; - scoped_ptr > io_client_weak_factory_; - base::Thread gst_thread_; - int bitstream_buffer_id_; -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - scoped_refptr pixmap_surface_; - int pixmap_id_; - gint gst_width_; - gint gst_height_; - Ecore_X_Damage damage_; - Ecore_Event_Handler* damage_handler_; - bool is_x_window_handle_set_; - typedef std::map > PixmapSurfaceTizenMap; - PixmapSurfaceTizenMap xpixmap_buffer_map_; -#else - int caps_width_; - int caps_height_; -#endif -}; - -TizenVideoDecodeAccelerator::TizenVideoDecodeAccelerator() - : impl_(NULL) { -} - -TizenVideoDecodeAccelerator::~TizenVideoDecodeAccelerator() { -} - -bool TizenVideoDecodeAccelerator::Initialize( - media::VideoCodecProfile profile, - Client* client) { - GError* error = NULL; - GstCaps* video_caps = NULL; - GstElement* gst_decoder = NULL; - GstElement* gst_parser = NULL; - GstBus* gst_bus = NULL; - GstPad* video_sink_pad = NULL; -#if !defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - GstElement* video_filter_ = NULL; - GstElement* gst_converter = NULL; -#endif - scoped_ptr gst_pipeline; - static GstAppSrcCallbacks appsrc_callbacks = - {&Impl::StartFeed, &Impl::StopFeed, NULL}; - CHECK(impl_ == NULL); - impl_ = new Impl(); - impl_->io_client_weak_factory_.reset( - new base::WeakPtrFactory(client)); - - switch (profile) { - case media::H264PROFILE_BASELINE: - DVLOG(1) << "Initialize(): profile -> H264PROFILE_BASELINE"; - break; - case media::H264PROFILE_MAIN: - DVLOG(1) << "Initialize(): profile -> H264PROFILE_MAIN"; - break; - default: - LOG(ERROR) << "Initialize(): unsupported profile=" << profile; - return false; - }; - - if (!gst_is_initialized() && !gst_init_check(NULL, NULL, &error)) { - LOG(ERROR) << __FUNCTION__ << "cannot initialize gstreamer."; - g_error_free(error); - return false; - } - - // pipeline initialization. - gst_pipeline.reset(gst_pipeline_new("h264_decode")); - if (!gst_pipeline) { - LOG(ERROR) << __FUNCTION__ << "cannot initialize gst pipeline."; - return false; - } - if (!(gst_bus = gst_pipeline_get_bus(GST_PIPELINE(gst_pipeline.get())))) { - return false; - } -#if GST_VERSION_MAJOR == 1 - gst_bus_set_sync_handler(gst_bus, Impl::OnBusMessage, impl_, NULL); -#else - gst_bus_set_sync_handler(gst_bus, Impl::OnBusMessage, impl_); -#endif - gst_object_unref(gst_bus); - - // appsrc initialization. - if (!(impl_->appsrc_ = gst_element_factory_make("appsrc", "src"))) { - LOG(ERROR) << __FUNCTION__ << "cannot initialize gst appsrc."; - return false; - } - if (!gst_bin_add(GST_BIN(gst_pipeline.get()), impl_->appsrc_)) { - gst_object_unref(impl_->appsrc_); - impl_->appsrc_ = NULL; - return false; - } - gst_app_src_set_max_bytes(GST_APP_SRC(impl_->appsrc_), INPUT_BUFFER_SIZE); - gst_app_src_set_callbacks(GST_APP_SRC(impl_->appsrc_), &appsrc_callbacks, - static_cast(impl_), NULL); - g_object_set(G_OBJECT(impl_->appsrc_), - "is-live", TRUE, - "block", FALSE, - "min-percent", 80, // if buffer below 80%, need-data emits. - "stream-type", GST_APP_STREAM_TYPE_STREAM, - NULL); - if (!(video_caps = gst_caps_from_string("video/x-h264,framerate=30/1"))) { - return false; - } - gst_app_src_set_caps(GST_APP_SRC(impl_->appsrc_), video_caps); - gst_caps_unref(video_caps); - -#if defined(OS_TIZEN) - DVLOG(1) << "######################################"; - DVLOG(1) << " USING omx_h264dec DECODER " << (unsigned int)this; - DVLOG(1) << "######################################"; - - // parser initialization - if (!(gst_parser = gst_element_factory_make("h264parse", "h264parse"))) { - LOG(ERROR) << " cannot create h264parse."; - return false; - } - if(!gst_bin_add(GST_BIN(gst_pipeline.get()), gst_parser)) { - LOG(ERROR) << " cannot add h264parse into decoder pipeline."; - gst_object_unref(gst_parser); - return false; - } - - // decoder initialization. - if (!(gst_decoder = gst_element_factory_make(kDecoderGstElement, kDecoderName))) { - LOG(ERROR) << " cannot create " << kDecoderGstElement << "."; - return false; - } - if (!gst_bin_add(GST_BIN(gst_pipeline.get()), gst_decoder)) { - LOG(ERROR) << " cannot add " << kDecoderGstElement << " to pipeline."; - gst_object_unref(gst_decoder); - return false; - } -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - // sink initialization. - if (!(impl_->sink_ = gst_element_factory_make("xvimagesink", "xvimagesink"))) { - LOG(ERROR) << __FUNCTION__ << " cannot create xvimagesink."; - return false; - } - if (!gst_bin_add(GST_BIN(gst_pipeline.get()), impl_->sink_)) { - gst_object_unref(impl_->sink_); - impl_->sink_ = NULL; - return false; - } - g_object_set(impl_->sink_, "rotate", 0, NULL); - - if (!(video_sink_pad = gst_element_get_static_pad(impl_->sink_, "sink"))) { - return false; - } - g_signal_connect(video_sink_pad, "notify::caps", - G_CALLBACK(impl_->OnSinkCapChanged), - impl_); - impl_->SetXWindowHandle(false); - gst_object_unref(video_sink_pad); - - // linking the elements. - if (!gst_element_link(impl_->appsrc_, gst_parser)) { - LOG(ERROR) << " Source and gst_parser could not be linked"; - return false; - } - - if (!gst_element_link(gst_parser, gst_decoder)) { - LOG(ERROR) << " gst_parser and Decoder could not be linked"; - return false; - } - if (!gst_element_link(gst_decoder, impl_->sink_)) { - LOG(ERROR) << __FUNCTION__ << " Decoder and Sink could not be linked"; - return false; - } -#else - impl_->CreateAppSinkElement(); - if (!impl_->sink_) { - LOG(ERROR) << "Could not create and add appsink element"; - return false; - } - if (!gst_bin_add(GST_BIN(gst_pipeline.get()), impl_->sink_)) { - gst_object_unref(impl_->sink_); - impl_->sink_ = NULL; - return false; - } - if (!(gst_converter = gst_element_factory_make("fimcconvert", "cvt"))) { - LOG(ERROR) << __FUNCTION__ << " cannot create fimcconvert."; - return false; - } - if(!gst_bin_add(GST_BIN(gst_pipeline.get()), gst_converter)) { - LOG(ERROR) << __FUNCTION__ << " cannot add fimcconvert into pipeline."; - gst_object_unref(gst_converter); - return false; - } - if (!(video_filter_ = gst_element_factory_make("capsfilter", "VideoFilter"))) { - LOG(ERROR) << __FUNCTION__ << " cannot create capsfilter."; - return false; - } - if(!gst_bin_add(GST_BIN(gst_pipeline.get()), video_filter_)) { - LOG(ERROR) << __FUNCTION__ << " cannot add videoFilter into pipeline."; - gst_object_unref(video_filter_); - return false; - } - - // FIXME: SONAL - // OnSinkCapChanged callback is not coming for Appsink implementation - if (!(video_sink_pad = - gst_element_get_static_pad(impl_->sink_, "sink"))) { - LOG(ERROR) << "Could not create video sink pad"; - return false; - } - g_signal_connect( - video_sink_pad, "notify::caps", - G_CALLBACK(&Impl::OnSinkCapChanged), impl_); - gst_object_unref(video_sink_pad); - if (!gst_element_link_many(impl_->appsrc_, - gst_parser, - gst_decoder, - gst_converter, - video_filter_, - impl_->sink_, - NULL)) { - LOG(ERROR) << __FUNCTION__ << " cannot link some elements in decode pipeline"; - return false; - } - g_object_set(G_OBJECT(video_filter_), - "caps", - gst_caps_new_simple("video/x-raw","format", G_TYPE_STRING, "I420",NULL), - NULL); -#endif -#else - DVLOG(1) << "######################################"; - DVLOG(1) << " USING ffdec_h264 DECODER"; - DVLOG(1) << "######################################"; - GstElement* gst_colorspace = NULL; - - // decoder initialization - if (!(gst_decoder = gst_element_factory_make("ffdec_h264", "H264-decoder"))) { - LOG(ERROR) << __FUNCTION__ << " cannot create ffdec_h264."; - return false; - } - if (!gst_bin_add(GST_BIN(gst_pipeline.get()), gst_decoder)) { - gst_object_unref(gst_decoder); - return false; - } - - // colorspace initialization - if (!(gst_colorspace = gst_element_factory_make("ffmpegcolorspace", "cs"))) { - LOG(ERROR) << __FUNCTION__ << " cannot create ffmpegcolorspace."; - return false; - } - if (!gst_bin_add(GST_BIN(gst_pipeline.get()), gst_colorspace)) { - gst_object_unref(gst_colorspace); - return false; - } - - if (!(impl_->sink_ = gst_element_factory_make("autovideosink", "sink"))) { - LOG(ERROR) << __FUNCTION__ << " cannot create autovideosink."; - return false; - } - if (!gst_bin_add(GST_BIN(gst_pipeline.get()), impl_->sink_)) { - gst_object_unref(impl_->sink_); - impl_->sink_ = NULL; - return false; - } - - if(!gst_element_link_many(impl_->appsrc_, gst_decoder, gst_colorspace, - impl_->sink_, NULL)) { - LOG(ERROR) << __FUNCTION__ << " Some element could not be linked"; - return false; - } -#endif - if (!impl_->gst_thread_.Start()) { - LOG(ERROR) << __FUNCTION__ << " gst_thread_ failed to start"; - return false; - } - - impl_->gst_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TizenVideoDecodeAccelerator::StartDecoder, - base::Unretained(this))); - - GST_DEBUG_BIN_TO_DOT_FILE( - GST_BIN(gst_pipeline.get()), GST_DEBUG_GRAPH_SHOW_ALL, "decoder_graph.dot"); - - impl_->pipeline_ = gst_pipeline.release(); - return true; -} - -void TizenVideoDecodeAccelerator::Decode( - const media::BitstreamBuffer& bitstream_buffer) { - scoped_ptr buffer_ref; - scoped_ptr shm( - new base::SharedMemory(bitstream_buffer.handle(), true)); - - if (!shm->Map(bitstream_buffer.size())) { - LOG(ERROR) << __FUNCTION__ << " could not map bitstream_buffer"; - NotifyError(media::VideoDecodeAccelerator::UNREADABLE_INPUT); - return; - } - - buffer_ref.reset(new BitstreamBufferRef( - impl_->io_client_weak_factory_->GetWeakPtr(), - base::MessageLoopProxy::current(), - shm.release(), - bitstream_buffer.size(), - bitstream_buffer.id())); - - if (!buffer_ref) { - return; - } - - if (impl_->can_feed_ && !impl_->is_destroying_) { - impl_->gst_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TizenVideoDecodeAccelerator::OnDecode, - base::Unretained(this), - base::Passed(&buffer_ref))); - } else { - DVLOG(2) << __FUNCTION__ - << " Frame drop on decoder:" - << " INPUT Q is FULL"; - } -} - -void TizenVideoDecodeAccelerator::AssignPictureBuffers( - const std::vector& buffers) { - NOTIMPLEMENTED(); -} - -void TizenVideoDecodeAccelerator::ReusePictureBuffer( - int32 picture_buffer_id) { - NOTIMPLEMENTED(); -} - -void TizenVideoDecodeAccelerator::Flush() { - NOTIMPLEMENTED(); -} - -void TizenVideoDecodeAccelerator::Reset() { - NOTIMPLEMENTED(); -} - -void TizenVideoDecodeAccelerator::Destroy() { - if (impl_ != NULL) { -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - impl_->SetXWindowHandle(false); - impl_->DeregisterDamageHandler(); - impl_->xpixmap_buffer_map_.clear(); -#endif - if (impl_->gst_thread_.IsRunning()) { - impl_->gst_thread_.Stop(); - } - gst_app_src_end_of_stream(GST_APP_SRC(impl_->appsrc_)); - impl_->is_destroying_ = true; - if (impl_->pipeline_) { - gst_element_set_state(impl_->pipeline_, GST_STATE_NULL); - gst_object_unref(GST_OBJECT(impl_->pipeline_)); - } - delete impl_; - impl_ = NULL; - } - delete this; -} - -bool TizenVideoDecodeAccelerator::CanDecodeOnIOThread(){ - return false; -} - -void TizenVideoDecodeAccelerator::StartDecoder() { - gst_element_set_state(impl_->pipeline_, GST_STATE_PLAYING); -}; - -#if !defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -void TizenVideoDecodeAccelerator::Impl::OnSinkCapChanged( - GstPad* sink_pad, GParamSpec* gparamspec, void* user_data) { - content::TizenVideoDecodeAccelerator::Impl* impl = - static_cast(user_data); - int width = 0, height = 0; -#if GST_VERSION_MAJOR == 1 - GstCaps* caps = gst_pad_get_current_caps(GST_PAD(sink_pad)); - if (caps) { - GstVideoInfo info; - gst_video_info_init(&info); - if (gst_video_info_from_caps(&info, caps)) { - if ((impl->caps_width_ != width) || (impl->caps_height_ != height)) { - impl->caps_width_ = info.width; - impl->caps_height_ = info.height; - } - } - } -#else - if (gst_video_get_size(sink_pad, &width, &height)) { - if ((impl->caps_width_ != width) || (impl->caps_height_ != height)) { - impl->caps_width_ = width; - impl->caps_height_ = height; - } - } -#endif -} - -GstFlowReturn TizenVideoDecodeAccelerator::Impl::OnDecoded( - GstAppSink* sink, gpointer app_data) { - GstBuffer* gst_output_buf = NULL; - content::TizenVideoDecodeAccelerator::Impl* self = - static_cast(app_data); - // FIXME: SONAL - // Once OnSinkCapChanged callback startes coming dont find height - // and width for all buffers, move this code under if block -#if GST_VERSION_MAJOR == 1 - GstSample* sample = gst_app_sink_pull_sample(GST_APP_SINK(sink)); - gst_output_buf = gst_sample_get_buffer(sample); - GstMapInfo map; - if (!gst_buffer_map(gst_output_buf, &map, GST_MAP_READ)) - LOG (ERROR) << "Decoded Buffer contains invalid or no info!"; - GstCaps* caps = gst_sample_get_caps(sample); -#else - gst_output_buf = gst_app_sink_pull_buffer(GST_APP_SINK(sink)); - GstCaps* caps = gst_buffer_get_caps(GST_BUFFER(gst_output_buf)); -#endif - if (!self->caps_width_ || !self->caps_height_) { - if (!caps) { - LOG(ERROR) << __FUNCTION__ << "Could not fetch caps from buffer"; - gst_buffer_unref(gst_output_buf); - return GST_FLOW_ERROR; - } else { - // No need to unref |GstStructure| - const GstStructure* str = gst_caps_get_structure(caps, 0); - if (!str) { - gst_buffer_unref(gst_output_buf); - gst_caps_unref(caps); - return GST_FLOW_ERROR; - } - if (!gst_structure_get_int(str, "width", &self->caps_width_) || - !gst_structure_get_int(str, "height", &self->caps_height_)) { - LOG(ERROR) << "Buffer information could not be obtained"; - gst_buffer_unref(gst_output_buf); - gst_caps_unref(caps); - return GST_FLOW_ERROR; - } - gst_caps_unref(caps); - } - } - - if (gst_output_buf) { -#if GST_VERSION_MAJOR == 1 - if (map.data) { -#else - if (gst_output_buf->data) { -#endif - gfx::Rect frame_size = - gfx::Rect(self->caps_width_, self->caps_height_); - self->gst_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TizenVideoDecodeAccelerator::Impl::DeliverVideoFrame, - base::Unretained(self), - gst_output_buf, - self->bitstream_buffer_id_, - frame_size)); - self->bitstream_buffer_id_ = (self->bitstream_buffer_id_ + 1) & ID_LAST; - } - } else { - gst_buffer_unref(gst_output_buf); -#if GST_VERSION_MAJOR == 1 - gst_sample_unref(sample); -#endif - LOG(ERROR) << __FUNCTION__ - << " DECODING FRAME FAILED : frame_id" - << self->bitstream_buffer_id_; - } -#if GST_VERSION_MAJOR == 1 - gst_buffer_unmap(gst_output_buf, &map); -#endif - return GST_FLOW_OK; -} - - -void TizenVideoDecodeAccelerator::Impl::CreateAppSinkElement() { - GstAppSinkCallbacks appsink_callbacks = - {NULL, NULL, &OnDecoded, NULL}; - - if (!(sink_ = gst_element_factory_make("appsink", "sink"))) { - LOG(ERROR) << __FUNCTION__ << "Appsink could not be created"; - return; - } - gst_app_sink_set_callbacks(GST_APP_SINK(sink_), - &appsink_callbacks, - static_cast(this), - NULL); - gst_app_sink_set_max_buffers(GST_APP_SINK(sink_), 1); -} - -void TizenVideoDecodeAccelerator::Impl::DeliverVideoFrame( - GstBuffer* buffer, - int32 bitstream_buffer_id, - gfx::Rect frame_size) { - base::SharedMemory shared_memory; - base::SharedMemoryHandle shared_memory_handle; - -#if GST_VERSION_MAJOR == 1 - GstMapInfo map; - if (!gst_buffer_map(buffer, &map, GST_MAP_READ)) { - LOG (ERROR) << "Encoded Buffer contains invalid or no info.!"; - return; - } - uint32 buffer_size = map.size; -#else - uint32 buffer_size = buffer->size; -#endif - if (!shared_memory.CreateAndMapAnonymous(buffer_size)) { - LOG (ERROR) << "Shared Memory creation failed."; - } else { - if (!shared_memory.ShareToProcess(base::GetCurrentProcessHandle(), - &shared_memory_handle)) { - LOG(ERROR) << __FUNCTION__ << "Could not get handle of Shared Memory"; - } else { - memcpy(shared_memory.memory(), -#if GST_VERSION_MAJOR == 1 - map.data, -#else - GST_BUFFER_DATA(buffer), -#endif - buffer_size); - io_message_loop_proxy_->PostTask( - FROM_HERE, - base::Bind(&media::VideoDecodeAccelerator::Client::NotifyDecodeDone, - io_client_weak_factory_->GetWeakPtr(), - shared_memory_handle, - bitstream_buffer_id_, - buffer_size, - frame_size)); - } - } -#if GST_VERSION_MAJOR == 1 - gst_buffer_unmap(buffer, &map); -#endif - gst_buffer_unref(buffer); -} -#endif - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -void TizenVideoDecodeAccelerator::Impl::OnXWindowIdPrepared( - GstMessage* message) { -#if GST_VERSION_MAJOR == 1 - const GstStructure* structure = gst_message_get_structure(message); - gst_structure_get_int(structure, "video-width", &gst_width_); - gst_structure_get_int(structure, "video-height", &gst_height_); -#else - gst_structure_get_int(message->structure, "video-width", &gst_width_); - gst_structure_get_int(message->structure, "video-height", &gst_height_); -#endif - SetPixmap(gst_width_, gst_height_); - SetXWindowHandle(true); -} - -void TizenVideoDecodeAccelerator::Impl::SetXWindowHandle( - bool handle_set) { - is_x_window_handle_set_ = handle_set; -} - -void TizenVideoDecodeAccelerator::Impl::SetPixmap( - const int32& gst_width, const int32& gst_height) { - int32 key_wh = ConvertWidthAndHeightToKey(gst_width, gst_height); - PixmapSurfaceTizenMap::iterator it = xpixmap_buffer_map_.find(key_wh); - if (it != xpixmap_buffer_map_.end()) { - pixmap_surface_ = it->second; - pixmap_id_ = pixmap_surface_->GetId(); - } else { - pixmap_surface_ = - gfx::EflPixmap::Create(gfx::EflPixmapBase::UsageType::SURFACE, - gfx::Size(gst_width, gst_height)); - if (pixmap_surface_.get() == NULL) { - LOG(ERROR) << __FUNCTION__ << "Failed to create pixmap Surface"; - return; - } - pixmap_id_ = pixmap_surface_->GetId(); - xpixmap_buffer_map_[key_wh] = pixmap_surface_; - } - gst_width_ = gst_width; - gst_height_ = gst_height; - DeregisterDamageHandler(); - - // Register to get notification from ecore for damage updates. - damage_ = ecore_x_damage_new(pixmap_id_, - ECORE_X_DAMAGE_REPORT_RAW_RECTANGLES); - damage_handler_ = ecore_event_handler_add(ECORE_X_EVENT_DAMAGE_NOTIFY, - OnSurfaceChanged, - this); -#if GST_VERSION_MAJOR == 1 - gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(sink_), pixmap_id_); -#else - gst_x_overlay_set_window_handle(GST_X_OVERLAY(sink_), pixmap_id_); -#endif -} - -void TizenVideoDecodeAccelerator::Impl::DeregisterDamageHandler() { - if (damage_) { - ecore_x_damage_free(damage_); - damage_ = 0; - } - if (damage_handler_) { - ecore_event_handler_del(damage_handler_); - damage_handler_ = NULL; - } -} - -// Callback received when pixmap surface is changed/damaged -Eina_Bool TizenVideoDecodeAccelerator::Impl::OnSurfaceChanged(void* ptr_acc, - int type, - void* event) { - TizenVideoDecodeAccelerator::Impl* self = - static_cast(ptr_acc); - - if (self) { - media::Picture picture(self->pixmap_id_, - self->bitstream_buffer_id_, - gfx::Rect(self->gst_width_, self->gst_height_)); - - self->io_message_loop_proxy_->PostTask( - FROM_HERE, - base::Bind(&media::VideoDecodeAccelerator::Client::PictureReady, - self->io_client_weak_factory_->GetWeakPtr(), - picture) ); - self->bitstream_buffer_id_ = (self->bitstream_buffer_id_ + 1) & ID_LAST; - } else { - LOG(ERROR) << __FUNCTION__ << "Accelerator is NULL"; - return ECORE_CALLBACK_CANCEL; - } - return ECORE_CALLBACK_PASS_ON; -} - -void TizenVideoDecodeAccelerator::Impl::OnSinkCapChanged( - GstPad* sink_pad, GParamSpec* gparamspec,void* user_data) { - TizenVideoDecodeAccelerator::Impl* self = - static_cast(user_data); - if (!self) { - LOG(ERROR) << __FUNCTION__ << "Accelerator is NULL"; - return; - } - - int width = 0, height = 0; -#if GST_VERSION_MAJOR == 1 - GstCaps* caps = gst_pad_get_current_caps(GST_PAD(sink_pad)); - if (caps) { - GstVideoInfo info; - gst_video_info_init(&info); - - if (gst_video_info_from_caps(&info, caps)) { - width = info.width; - height = info.height; - if ((self->gst_width_ != width) || (self->gst_height_ != height)) { - self->SetPixmap(width, height); - } - } - } -#else - if (gst_video_get_size(sink_pad, &width, &height)) { - if ((self->gst_width_ != width) || (self->gst_height_ != height)) { - self->SetPixmap(width, height); - } - } -#endif -} -#endif - -void TizenVideoDecodeAccelerator::OnDecode( - scoped_ptr buffer_ref) { - if (!buffer_ref) { - return; - } -#if GST_VERSION_MAJOR == 1 - buffer_ref->gst_buffer_ = - gst_buffer_new_wrapped_full(GST_MEMORY_FLAG_READONLY, - static_cast(buffer_ref->shm_->memory()), - buffer_ref->size_, - 0, - buffer_ref->size_, - reinterpret_cast(buffer_ref.get()), - BitstreamBufferRef::Destruct); - if (!buffer_ref->gst_buffer_ || !GST_IS_BUFFER(buffer_ref->gst_buffer_)) { - LOG(ERROR) << " gst_buffer_new_wrapped_full failed to allocate memory.!"; - return; - } -#else - if (!(buffer_ref->gst_buffer_ = gst_buffer_new())) { - return; - } - - GST_BUFFER_MALLOCDATA(buffer_ref->gst_buffer_) = - reinterpret_cast(buffer_ref.get()); - GST_BUFFER_FREE_FUNC(buffer_ref->gst_buffer_) = BitstreamBufferRef::Destruct; - GST_BUFFER_SIZE(buffer_ref->gst_buffer_) = buffer_ref->size_; - GST_BUFFER_DATA(buffer_ref->gst_buffer_) = - static_cast(buffer_ref->shm_->memory()); -#endif - if (GST_FLOW_OK != - gst_app_src_push_buffer(GST_APP_SRC(impl_->appsrc_), - buffer_ref->gst_buffer_)) { - LOG(ERROR) << __FUNCTION__ << " fail to push buffer into decoder pipeline"; - return; - } - - // lifecycle of buffer_ref will be handled by gstreamer. - buffer_ref.release(); -} - -void TizenVideoDecodeAccelerator::NotifyError( - media::VideoDecodeAccelerator::Error error) { - if (impl_->io_client_weak_factory_->GetWeakPtr()) { - impl_->io_client_weak_factory_->GetWeakPtr()->NotifyError(error); - } -} - -} // namespace content - diff --git a/tizen_src/impl/content/common/gpu/media/tizen/tizen_video_decode_accelerator.h b/tizen_src/impl/content/common/gpu/media/tizen/tizen_video_decode_accelerator.h deleted file mode 100644 index c312e5e589b4..000000000000 --- a/tizen_src/impl/content/common/gpu/media/tizen/tizen_video_decode_accelerator.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_COMMON_GPU_MEDIA_TIZEN_VIDEO_DECODE_ACCELERATOR_H_ -#define CONTENT_COMMON_GPU_MEDIA_TIZEN_VIDEO_DECODE_ACCELERATOR_H_ - -#include -#include -#include -#include -#include -#include - -#include "base/synchronization/lock.h" -#include "base/threading/thread.h" -#include "content/common/content_export.h" -#include "media/video/video_decode_accelerator.h" - -namespace content { - -class CONTENT_EXPORT TizenVideoDecodeAccelerator - : public media::VideoDecodeAccelerator { - public: - TizenVideoDecodeAccelerator(); - ~TizenVideoDecodeAccelerator() override; - - bool Initialize(media::VideoCodecProfile profile, Client* client) override; - void Decode(const media::BitstreamBuffer& bitstream_buffer) override; - void AssignPictureBuffers( - const std::vector& buffers) override; - void ReusePictureBuffer(int32 picture_buffer_id) override; - void Flush() override; - void Reset() override; - void Destroy() override; - bool CanDecodeOnIOThread() override; - - private: - struct BitstreamBufferRef; - struct Impl; - - void OnDecode(scoped_ptr buffer_ref); - void NotifyError(media::VideoDecodeAccelerator::Error error); - void StartDecoder(); - - Impl* impl_; - - DISALLOW_COPY_AND_ASSIGN(TizenVideoDecodeAccelerator); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_MEDIA_TIZEN_VIDEO_DECODE_ACCELERATOR_H_ diff --git a/tizen_src/impl/content/common/gpu/media/tizen/tizen_video_encode_accelerator.cc b/tizen_src/impl/content/common/gpu/media/tizen/tizen_video_encode_accelerator.cc deleted file mode 100644 index 2db7941b9fd6..000000000000 --- a/tizen_src/impl/content/common/gpu/media/tizen/tizen_video_encode_accelerator.cc +++ /dev/null @@ -1,719 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/common/gpu/media/tizen/tizen_video_encode_accelerator.h" - -#include -#include -#include -#include - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/logging.h" -#include "base/message_loop/message_loop.h" -#include "base/timer/timer.h" -#include "gpu/command_buffer/service/gpu_switches.h" -#include "media/base/bitstream_buffer.h" -#include "third_party/webrtc/common_video/libyuv/include/webrtc_libyuv.h" - -using media::VideoFrame; - -namespace content { - -struct GstBufferDeleter { - inline void operator()(GstBuffer* ptr) const { - DCHECK(ptr != NULL); - gst_buffer_unref(ptr); - } -}; - -struct GstElementDeleter { - inline void operator()(GstElement* ptr) const { - DCHECK(ptr != NULL); - gst_object_unref(ptr); - } -}; - -enum { - // Arbitrary choice. - INITIAL_FRAMERATE = 30, - // Until there are non-realtime users, no need for unrequested I-frames. - INPUT_BUFFER_COUNT = 5, // default input buffer counts of omx_h264enc - MAX_BUFFERING = 60, - MAX_FRAME_RATE = 30, - // Max bitrate in bps - MAX_BITRATE = 2000000, - MAX_OUTPUT_BUFFERS = 30 // Maximum queue size of output buffers -}; -// Gstreamer elements and names. -const char* kEncoderName = "encoder"; -const char* kConvertorName = "cvt"; -#if GST_VERSION_MAJOR == 1 -const char* kEncoderGstElement = "omxh264enc"; -const char* kConvertorGstElement = "fimcconvert"; -#else -const char* kEncoderGstElement = "omx_h264enc"; -const char* kConvertorGstElement = "c2dconvert"; -#endif - - -media::VideoEncodeAccelerator* CreateTizenVideoEncodeAccelerator() { - return new TizenVideoEncodeAccelerator(); -} - -struct TizenVideoEncodeAccelerator::BitstreamBufferRef { - BitstreamBufferRef( - const scoped_refptr& frame, - base::WeakPtr client_delegate, - const scoped_refptr& client_message_loop_proxy, - size_t size) - : frame_(frame), - client_delegate_(client_delegate), - client_message_loop_proxy_(client_message_loop_proxy), - size_(size), - bytes_used_(0), - gst_buffer_(NULL) {} - - ~BitstreamBufferRef() {} - - static void Destruct(gpointer data) { - DCHECK(data != NULL); - BitstreamBufferRef* pRef = static_cast(data); - delete pRef; - } - - scoped_refptr frame_; - base::WeakPtr client_delegate_; - scoped_refptr client_message_loop_proxy_; - size_t size_; - off_t bytes_used_; - GstBuffer* gst_buffer_; -}; - -struct TizenVideoEncodeAccelerator::OutputBuffer { - explicit OutputBuffer( - GstBuffer* buffer, - bool key_frame) - : buffer_(buffer), - key_frame_(key_frame) {} - - virtual ~OutputBuffer() { - if(buffer_) - gst_buffer_unref(buffer_); - } - - GstBuffer* buffer_; - bool key_frame_; -}; - -struct TizenVideoEncodeAccelerator::Impl { - Impl(media::VideoEncodeAccelerator::Client* client, - scoped_refptr msg_loop) - : pipeline_(NULL), - encoder_(NULL), - appsrc_(NULL), - gst_thread_("GSTEncoder"), - enable_framedrop_(false), - io_client_weak_factory_(client), - child_message_loop_proxy_(msg_loop), - gst_bitrate_(0), - is_running_(false), - is_destroying_(false), - can_feed_(false) {} - - void DeliverVideoFrame(); - static GstFlowReturn OnEncoded(GstAppSink *sink,gpointer data); - static void StartFeed(GstAppSrc *source, guint size, gpointer data); - static void StopFeed(GstAppSrc *source, gpointer data); - - GstElement* pipeline_; - GstElement* encoder_; - GstElement* appsrc_; - base::Thread gst_thread_; - bool enable_framedrop_; - std::vector encoder_output_queue_; - base::WeakPtrFactory io_client_weak_factory_; - const scoped_refptr child_message_loop_proxy_; - base::Lock destroy_lock_; - base::ThreadChecker thread_checker_; - gfx::Size view_size_; - uint32 gst_bitrate_; - volatile bool is_running_; - volatile bool is_destroying_; - volatile bool can_feed_; - base::RepeatingTimer io_timer_; - std::queue output_buffers_; - base::Lock output_queue_lock_; -}; - -void TizenVideoEncodeAccelerator::Impl::DeliverVideoFrame() { - media::BitstreamBuffer* bs_buffer = NULL; - GstBuffer* buffer = NULL; - bool key_frame = false; - gsize gst_buffer_size = 0; -#if GST_VERSION_MAJOR == 1 - GstMapInfo map; -#endif - - scoped_ptr shm; - - if(output_buffers_.empty()) - return; - - if (encoder_output_queue_.empty()) { - // Observed till now that output_buffers_ size does not exceed 4-5. - // Therefore this code will be called in very rare situations. - if(output_buffers_.size() >= MAX_OUTPUT_BUFFERS) { - enable_framedrop_ = true; - TizenVideoEncodeAccelerator::OutputBuffer* drop_buffer = NULL; - { - base::AutoLock auto_lock(output_queue_lock_); - while(!output_buffers_.empty()) { - drop_buffer = output_buffers_.front(); - if (drop_buffer->key_frame_) - break; - output_buffers_.pop(); - gst_buffer_unref(drop_buffer->buffer_); - delete drop_buffer; - } - } - return; - } - return; - } - enable_framedrop_ = false; - key_frame = output_buffers_.front()->key_frame_; - bs_buffer = &encoder_output_queue_.back(); - encoder_output_queue_.pop_back(); - - shm.reset(new base::SharedMemory(bs_buffer->handle(), false)); - if (!shm->Map(bs_buffer->size())) { - LOG(ERROR) << "Failed to map SHM"; - io_client_weak_factory_.GetWeakPtr()->NotifyError( - media::VideoEncodeAccelerator::kPlatformFailureError); - gst_buffer_unref(buffer); - } - - { - base::AutoLock auto_lock(output_queue_lock_); - buffer = output_buffers_.front()->buffer_; - output_buffers_.pop(); - } -#if GST_VERSION_MAJOR == 1 - if (!gst_buffer_map(buffer, &map, GST_MAP_READ)) { - LOG (ERROR) << "Encoded Buffer contains invalid or no info.!"; - return; - } - gst_buffer_size = map.size; -#else - gst_buffer_size = buffer->size; -#endif - - - if (gst_buffer_size > shm->mapped_size()) { - LOG(ERROR) << "Encoded buff too large: " - << gst_buffer_size << ">" << shm->mapped_size(); - io_client_weak_factory_.GetWeakPtr()->NotifyError( - media::VideoEncodeAccelerator::kPlatformFailureError); - gst_buffer_unref(buffer); - } - //copying data to shared memory. -#if GST_VERSION_MAJOR == 1 - memcpy(static_cast(shm->memory()), map.data, gst_buffer_size); - gst_buffer_unmap(buffer, &map); -#else - memcpy(static_cast(shm->memory()), buffer->data, gst_buffer_size); -#endif - - child_message_loop_proxy_->PostTask( - FROM_HERE, - base::Bind(&media::VideoEncodeAccelerator::Client::BitstreamBufferReady, - io_client_weak_factory_.GetWeakPtr(), - bs_buffer->id(), - gst_buffer_size, - key_frame)); -} - -GstFlowReturn TizenVideoEncodeAccelerator::Impl::OnEncoded( - GstAppSink *sink, gpointer data) { - bool key_frame = false; - GstBuffer* gst_output_buf = NULL; - TizenVideoEncodeAccelerator::Impl* impl = - static_cast(data); -#if GST_VERSION_MAJOR == 1 - gst_output_buf = gst_sample_get_buffer(gst_app_sink_pull_sample(GST_APP_SINK(sink))); - GstMapInfo map; - if (!gst_buffer_map(gst_output_buf, &map, GST_MAP_READ)) - LOG (ERROR) << "Encoded Buffer contains invalid or no info!"; -#else - gst_output_buf = gst_app_sink_pull_buffer(GST_APP_SINK(sink)); -#endif - - if (gst_output_buf) { - if (!GST_BUFFER_FLAG_IS_SET(gst_output_buf, GST_BUFFER_FLAG_DELTA_UNIT)) { - key_frame = true; - } -#if GST_VERSION_MAJOR == 1 - if (map.data) { -#else - if (gst_output_buf->data) { -#endif - base::AutoLock auto_lock(impl->output_queue_lock_); - impl->output_buffers_.push( - new TizenVideoEncodeAccelerator::OutputBuffer(gst_output_buf, - key_frame)); - } - } else { - LOG(ERROR) << __FUNCTION__ << " ENCODING FRAME FAILED"; - } -#if GST_VERSION_MAJOR == 1 - gst_buffer_unmap(gst_output_buf, &map); -#endif - return GST_FLOW_OK; -} - -void TizenVideoEncodeAccelerator::Impl::StartFeed( - GstAppSrc *source, guint size, gpointer data) { - TizenVideoEncodeAccelerator::Impl* impl = - static_cast(data); - DCHECK(impl); - impl->can_feed_ = true; -} - -void TizenVideoEncodeAccelerator::Impl::StopFeed( - GstAppSrc *source, gpointer data) { - TizenVideoEncodeAccelerator::Impl* impl = - static_cast(data); - DCHECK(impl); - impl->can_feed_ = false; -} - -TizenVideoEncodeAccelerator::TizenVideoEncodeAccelerator() - : impl_(NULL) {} - -TizenVideoEncodeAccelerator::~TizenVideoEncodeAccelerator() {} - -std::vector -TizenVideoEncodeAccelerator::GetSupportedProfiles() { - std::vector profiles; - media::VideoEncodeAccelerator::SupportedProfile profile; - profile.profile = media::H264PROFILE_BASELINE; - profile.max_resolution.SetSize(1280, 720); - profile.max_framerate_numerator = 30; - profile.max_framerate_denominator = 1; - profiles.push_back(profile); - - return profiles; -} - -bool TizenVideoEncodeAccelerator::Initialize( - media::VideoFrame::Format input_format, - const gfx::Size& input_visible_size, - media::VideoCodecProfile output_profile, - uint32 initial_bitrate, - Client* client) { - DVLOG(1) << __FUNCTION__ - << " size :" << input_visible_size.ToString() - << " max bitrate :" << MAX_BITRATE << "bps"; - DCHECK(impl_ == NULL); - if (media::H264PROFILE_MIN > output_profile || - media::H264PROFILE_MAX < output_profile) { - NOTREACHED(); - return false; - } - - impl_ = new Impl(client, base::MessageLoopProxy::current()); - impl_->gst_bitrate_ = initial_bitrate; - impl_->view_size_ = input_visible_size; - impl_->gst_thread_.Start(); - - if (!StartEncoder()) { - delete impl_; - impl_ = NULL; - return false; - } - - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&media::VideoEncodeAccelerator::Client::RequireBitstreamBuffers, - impl_->io_client_weak_factory_.GetWeakPtr(), - (unsigned int)INPUT_BUFFER_COUNT, - input_visible_size, - MAX_BITRATE / 8)); // Maximum bytes for a frame by MAX_BITRATE. - return true; -} - -void TizenVideoEncodeAccelerator::Encode( - const scoped_refptr& frame, - bool force_keyframe) { - size_t frame_size = VideoFrame::AllocationSize(VideoFrame::I420, - frame->coded_size()); - DVLOG(3) << __FUNCTION__ - << " coded_size :" << frame->coded_size().ToString() - << " natural_size :" << frame->natural_size().ToString(); - - scoped_ptr buffer_ref; - - buffer_ref.reset( - new BitstreamBufferRef(frame, - impl_->io_client_weak_factory_.GetWeakPtr(), - impl_->child_message_loop_proxy_, - frame_size)); - - if (!buffer_ref) { - LOG(ERROR) << __FUNCTION__ << "malloc failed"; - return; - } - - if (impl_->can_feed_ && !impl_->is_destroying_) { - impl_->gst_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TizenVideoEncodeAccelerator::OnEncode, - base::Unretained(this), - base::Passed(&buffer_ref), - force_keyframe)); - } else { - DVLOG(2) << __FUNCTION__ << " [WEBRTC] . FRAME DROP :" - << " can_feed_:" << impl_->can_feed_ - << " is_destroying_:" << impl_->is_destroying_; - } -} - -void TizenVideoEncodeAccelerator::UseOutputBitstreamBuffer( - const media::BitstreamBuffer& buffer) { - impl_->gst_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TizenVideoEncodeAccelerator::OnUseOutputBitstreamBuffer, - base::Unretained(this), - buffer)); -} - -void TizenVideoEncodeAccelerator::RequestEncodingParametersChange( - uint32 bitrate, uint32 framerate) { - DVLOG(2) << __FUNCTION__ - << " bitrate: " << bitrate - << " framerate: " << framerate; - if (bitrate > 0 && bitrate != impl_->gst_bitrate_) { - impl_->gst_bitrate_ = bitrate; - // Omx Encoder expects bitrate in bps whereas ffenc expects bitrate in kbps - // Information can be gained by gst-inspect -#if defined(OS_TIZEN) - g_object_set(G_OBJECT(impl_->encoder_), -#if GST_VERSION_MAJOR == 1 - "target-bitrate", -#else - "bitrate", -#endif - std::min(bitrate, static_cast(MAX_BITRATE)), - NULL); -#else - g_object_set(G_OBJECT(impl_->encoder_), - "bitrate", - std::min(bitrate, static_cast(MAX_BITRATE)) / 1000, - NULL); -#endif - } -} - -void TizenVideoEncodeAccelerator::Destroy() { - if (impl_) { - DCHECK(impl_->thread_checker_.CalledOnValidThread()); - if(impl_->appsrc_) - gst_app_src_end_of_stream(GST_APP_SRC(impl_->appsrc_)); - - { - base::AutoLock auto_lock(impl_->destroy_lock_); - impl_->is_destroying_ = true; - } - - if (impl_->gst_thread_.IsRunning()) - impl_->gst_thread_.Stop(); - if (impl_->pipeline_) { - gst_element_set_state(impl_->pipeline_, GST_STATE_NULL); - gst_object_unref(GST_OBJECT(impl_->pipeline_)); - } - if (impl_->io_timer_.IsRunning()) - impl_->io_timer_.Stop(); - - while (!impl_->encoder_output_queue_.empty()) { - media::BitstreamBuffer bitstream_buffer = impl_->encoder_output_queue_.back(); - // created shm and let it go out of scope automatically. - scoped_ptr shm( - new base::SharedMemory(bitstream_buffer.handle(), false)); - impl_->encoder_output_queue_.pop_back(); - } - while (!impl_->output_buffers_.empty()) { - OutputBuffer* output_buffer = impl_->output_buffers_.front(); - gst_buffer_unref(output_buffer->buffer_); - impl_->output_buffers_.pop(); - } - delete impl_; - } - delete this; -} - -void TizenVideoEncodeAccelerator::OnEncode( - scoped_ptr buffer_ref, bool force_keyframe) { - - BitstreamBufferRef* bufref = buffer_ref.release(); - if (bufref == NULL) { - return; - } - -#if defined(OS_TIZEN) && GST_VERSION_MAJOR != 1 - g_object_set(impl_->encoder_, - "force-i-frame", - (force_keyframe || impl_->enable_framedrop_) ? TRUE : FALSE, - NULL); -#endif - -#if GST_VERSION_MAJOR == 1 - bufref->gst_buffer_ = - gst_buffer_new_wrapped_full(GST_MEMORY_FLAG_READONLY, - static_cast(bufref->frame_->data(VideoFrame::kYPlane)), - bufref->size_, - 0, - bufref->size_, - reinterpret_cast(bufref), - BitstreamBufferRef::Destruct); - if (!bufref->gst_buffer_ || !GST_IS_BUFFER(bufref->gst_buffer_)) { - LOG(INFO) << " gst_buffer_new_wrapped_full failed to allocate memory."; - return; - } -#else - if (!(bufref->gst_buffer_ = gst_buffer_new())) { - LOG(ERROR) << __FUNCTION__ << " gst_buffer_new failed to allocate memory.!"; - return; - } - - GST_BUFFER_MALLOCDATA(bufref->gst_buffer_) = reinterpret_cast(bufref); - GST_BUFFER_FREE_FUNC(bufref->gst_buffer_) = BitstreamBufferRef::Destruct; - GST_BUFFER_SIZE(bufref->gst_buffer_) = bufref->size_; - GST_BUFFER_DATA(bufref->gst_buffer_) = - static_cast(bufref->frame_->data(VideoFrame::kYPlane)); -#endif - if (GST_FLOW_OK != - gst_app_src_push_buffer(GST_APP_SRC(impl_->appsrc_), - bufref->gst_buffer_)) { - LOG(ERROR) << __FUNCTION__ - << " error while pushing buffer int appsrc on encoder."; - gst_buffer_unref(bufref->gst_buffer_); - } - - return; -} - -void TizenVideoEncodeAccelerator::OnUseOutputBitstreamBuffer( - const media::BitstreamBuffer& buffer) { - impl_->encoder_output_queue_.push_back(buffer); - - DVLOG(2) << __FUNCTION__ - << " output buffer is ready to use: " << buffer.id() - << " out queue size: " << impl_->encoder_output_queue_.size(); -} - -bool TizenVideoEncodeAccelerator::StartEncoder() { - GError* error = NULL; - GstCaps* appsrc_caps = NULL; - GstElement* gst_appsink = NULL; - gboolean retval = FALSE; - scoped_ptr gst_pipeline; - - guint64 max_input_buffer = - INPUT_BUFFER_COUNT * VideoFrame::AllocationSize(VideoFrame::I420, - impl_->view_size_); - GstAppSrcCallbacks appsrc_callbacks = - { &TizenVideoEncodeAccelerator::Impl::StartFeed, - &TizenVideoEncodeAccelerator::Impl::StopFeed, - NULL }; - GstAppSinkCallbacks appsink_callbacks = - { NULL, NULL, &TizenVideoEncodeAccelerator::Impl::OnEncoded, NULL }; - - if (impl_->pipeline_ != NULL) { - return false; - } - - if (!gst_is_initialized() && !gst_init_check(NULL, NULL, &error)) { - LOG(ERROR) << __FUNCTION__ << " cannot initialize gstreamer."; - g_error_free(error); - return false; - } - - // pipeline initialization - gst_pipeline.reset(gst_pipeline_new("h264_encode")); - if (!gst_pipeline) { - LOG(ERROR) << __FUNCTION__ << " cannot initialize gst pipeline."; - return false; - } - - // appsrc initialization - if (!(impl_->appsrc_ = gst_element_factory_make ("appsrc", "src"))) { - LOG(ERROR) << __FUNCTION__ << "cannot initialize gst appsrc."; - return false; - } - if (!gst_bin_add(GST_BIN(gst_pipeline.get()), impl_->appsrc_)) { - LOG(ERROR) << __FUNCTION__ << " cannot add gst appsrc into encoder pipeline."; - gst_object_unref(impl_->appsrc_); - impl_->appsrc_ = NULL; - return false; - } - appsrc_caps = gst_caps_new_simple( -#if GST_VERSION_MAJOR == 1 - "video/x-raw", - "format", G_TYPE_STRING, gst_video_format_to_string(GST_VIDEO_FORMAT_I420), -#else - "video/x-raw-yuv", - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('I', '4', '2', '0'), -#endif - "width", G_TYPE_INT, impl_->view_size_.width(), - "height", G_TYPE_INT, impl_->view_size_.height(), - "framerate", GST_TYPE_FRACTION, 30, 1, - "rotate", G_TYPE_INT, 0, - NULL); - if (!appsrc_caps) { - LOG(ERROR) << __FUNCTION__ << " cannot create appsrc caps"; - return false; - } - gst_app_src_set_callbacks(GST_APP_SRC(impl_->appsrc_), &appsrc_callbacks, - static_cast(impl_), NULL); - gst_app_src_set_max_bytes(GST_APP_SRC(impl_->appsrc_), max_input_buffer); - gst_app_src_set_caps(GST_APP_SRC(impl_->appsrc_), appsrc_caps); - - // appsink initialization - if (!(gst_appsink = gst_element_factory_make("appsink", "sink"))) { - LOG(ERROR) << "cannot create appsink for encoder pipeline."; - return false; - } - if (!gst_bin_add(GST_BIN(gst_pipeline.get()), gst_appsink)) { - LOG(ERROR) << "cannot add gst appsink into encoder pipeline."; - gst_object_unref(gst_appsink); - return false; - } - gst_app_sink_set_callbacks(GST_APP_SINK(gst_appsink), &appsink_callbacks, - static_cast(impl_), NULL); - gst_app_sink_set_max_buffers(GST_APP_SINK(gst_appsink), 1); - -#ifdef OS_TIZEN - DVLOG(1) << "######################################"; - DVLOG(1) << " USING omx_h264enc ENCODER"; - DVLOG(1) << "######################################"; - - // encoder initialization - if (!(impl_->encoder_ = gst_element_factory_make(kEncoderGstElement, kEncoderName))) { - LOG(ERROR) << __FUNCTION__ << " cannot create " << kEncoderGstElement << "."; - return false; - } - if(!gst_bin_add(GST_BIN(gst_pipeline.get()), impl_->encoder_)) { - LOG(ERROR) << __FUNCTION__ << " cannot add omx_h264enc into encoder pipeline."; - gst_object_unref(impl_->encoder_); - impl_->encoder_ = NULL; - return false; - } - g_object_set(impl_->encoder_, - "control-rate", 2, // 1:VBR_CFR 2:CBR_CFR 3:VBR_VFR 4:CBR_VFR -#if GST_VERSION_MAJOR == 1 - "target-bitrate", impl_->gst_bitrate_, -#else - "encoder-profile", 1, // BASELINE_PROFILE - "byte-stream", TRUE, - "bitrate", impl_->gst_bitrate_, -#endif - NULL); - - g_object_set(G_OBJECT(impl_->appsrc_), - "is-live", TRUE, - "block", FALSE, - "do-timestamp", TRUE, - "min-latency", (gint64)(0), - "max-latency", (gint64)(0), - "min-percent", 80, // if buffer below 80%, need-data emits. - "stream-type", GST_APP_STREAM_TYPE_STREAM, - "format", GST_FORMAT_DEFAULT, - NULL); - - g_object_set(gst_appsink, "sync", FALSE, NULL); - - if (!gst_element_link(impl_->appsrc_, impl_->encoder_)) { - LOG(ERROR) << " cannot link impl_->appsrc_ with encoder_."; - return false; - } - - if (!gst_element_link(impl_->encoder_, gst_appsink)) { - LOG(ERROR) << " cannot link encoder_ to sink."; - return false; - } -#else - DVLOG(1) << "######################################"; - DVLOG(1) << " USING x264enc ENCODER"; - DVLOG(1) << "######################################"; - GstElement* gst_parser = NULL; - - // parser initialization - if (!(gst_parser = gst_element_factory_make("videoparse", "parse"))) { - LOG(ERROR) << __FUNCTION__ << " cannot create videoparse."; - return false; - } - if(!gst_bin_add(GST_BIN(gst_pipeline.get()), gst_parser)) { - LOG(ERROR) << __FUNCTION__ << " cannot add videoparse into encoder pipeline."; - gst_object_unref(gst_parser); - return false; - } - g_object_set(gst_parser, - "format", GST_VIDEO_FORMAT_I420, - "width", impl_->view_size_.width(), - "height", impl_->view_size_.height(), - "framerate", INITIAL_FRAMERATE, 1, - NULL); - - if (!(impl_->encoder_ = gst_element_factory_make ("x264enc","encoder"))) { - LOG(ERROR) << __FUNCTION__ << " cannot create x264enc encoder."; - return false; - } - if(!gst_bin_add(GST_BIN(gst_pipeline.get()), impl_->encoder_)) { - LOG(ERROR) << __FUNCTION__ << " cannot add x264enc into encoder pipeline."; - gst_object_unref(impl_->encoder_); - return false; - } - g_object_set(impl_->encoder_, - "byte-stream", TRUE, - "bitrate", impl_->gst_bitrate_, - "tune",0x00000004,"profile", 1, NULL); - - g_object_set(G_OBJECT(impl_->appsrc_), - "is-live", TRUE, - "block", FALSE, - "do-timestamp", TRUE, - "stream-type", 0, - "min-latency", (gint64)(0), - "max-latency", (gint64)(0), - "format", GST_FORMAT_TIME, - NULL); - - g_object_set(gst_appsink, "sync", FALSE, NULL); - - if (!gst_element_link_many(impl_->appsrc_, gst_parser, - impl_->encoder_, gst_appsink, NULL)) { - LOG(ERROR) << __FUNCTION__ << " cannot link for encoder pipeline."; - return false; - } -#endif - - if (GST_STATE_CHANGE_FAILURE == - gst_element_set_state(gst_pipeline.get(), GST_STATE_PLAYING)) { - LOG(ERROR) << __FUNCTION__ << " cannot start encoder pipeline."; - return false; - } - impl_->io_timer_.Start(FROM_HERE, - base::TimeDelta::FromMilliseconds(10), - impl_, - &TizenVideoEncodeAccelerator::Impl::DeliverVideoFrame); - GST_DEBUG_BIN_TO_DOT_FILE( - GST_BIN(gst_pipeline.get()), GST_DEBUG_GRAPH_SHOW_ALL, "encoder_graph.dot"); - - impl_->pipeline_ = gst_pipeline.release(); - return true; -} - -} // namespace content diff --git a/tizen_src/impl/content/common/gpu/media/tizen/tizen_video_encode_accelerator.h b/tizen_src/impl/content/common/gpu/media/tizen/tizen_video_encode_accelerator.h deleted file mode 100644 index 08218807775a..000000000000 --- a/tizen_src/impl/content/common/gpu/media/tizen/tizen_video_encode_accelerator.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_COMMON_GPU_MEDIA_TIZEN_VIDEO_ENCODE_ACCELERATOR_H_ -#define CONTENT_COMMON_GPU_MEDIA_TIZEN_VIDEO_ENCODE_ACCELERATOR_H_ - -#include "base/threading/thread.h" -#include "base/synchronization/lock.h" -#include "base/synchronization/waitable_event.h" -#include "content/common/content_export.h" -#include "media/video/video_encode_accelerator.h" - -namespace content { - -class CONTENT_EXPORT TizenVideoEncodeAccelerator - : public media::VideoEncodeAccelerator { - public: - TizenVideoEncodeAccelerator(); - ~TizenVideoEncodeAccelerator() override; - - std::vector - GetSupportedProfiles() override; - bool Initialize(media::VideoFrame::Format input_format, - const gfx::Size& input_visible_size, - media::VideoCodecProfile output_profile, - uint32 initial_bitrate, - Client* client) override; - void Encode(const scoped_refptr& frame, - bool force_keyframe) override; - void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer) override; - void RequestEncodingParametersChange(uint32 bitrate, - uint32 framerate) override; - void Destroy() override; - - private: - struct BitstreamBufferRef; - struct Impl; - struct OutputBuffer; - - void OnEncode(scoped_ptr buffer_ref, bool force_keyframe); - void OnUseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer); - bool StartEncoder(); - - Impl* impl_; - - DISALLOW_COPY_AND_ASSIGN(TizenVideoEncodeAccelerator); -}; - -} // namespace content - -#endif // CONTENT_COMMON_GPU_MEDIA_TIZEN_VIDEO_ENCODE_ACCELERATOR_TIZEN_H_ diff --git a/tizen_src/impl/content/common/media/tizen/media_player_messages_enums_tizen.h b/tizen_src/impl/content/common/media/tizen/media_player_messages_enums_tizen.h deleted file mode 100644 index c6f9f8ff58eb..000000000000 --- a/tizen_src/impl/content/common/media/tizen/media_player_messages_enums_tizen.h +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_COMMON_MEDIA_MEDIA_PLAYER_MESSAGES_ENUMS_TIZEN_H_ -#define CONTENT_COMMON_MEDIA_MEDIA_PLAYER_MESSAGES_ENUMS_TIZEN_H_ - -// Dictates which type of media playback is being initialized. -enum MediaPlayerHostMsg_Initialize_Type { - MEDIA_PLAYER_TYPE_URL, - MEDIA_PLAYER_TYPE_MEDIA_SOURCE, -}; - -#endif // CONTENT_COMMON_MEDIA_MEDIA_PLAYER_MESSAGES_ENUMS_TIZEN_H_ diff --git a/tizen_src/impl/content/common/media/tizen/media_player_messages_tizen.h b/tizen_src/impl/content/common/media/tizen/media_player_messages_tizen.h deleted file mode 100644 index 3e7fa97032e0..000000000000 --- a/tizen_src/impl/content/common/media/tizen/media_player_messages_tizen.h +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// IPC messages for tizen media player. -// Multiply-included message file, hence no include guard. - -#include "content/common/content_export.h" -#include "ipc/ipc_message_macros.h" -#include "media/base/media_keys.h" -#include "media/base/tizen/demuxer_stream_player_params_tizen.h" -#include "media/base/tizen/media_player_manager_tizen.h" -#include "ui/gfx/rect_f.h" - -#undef IPC_MESSAGE_EXPORT -#define IPC_MESSAGE_EXPORT CONTENT_EXPORT -#define IPC_MESSAGE_START MediaPlayerTizenMsgStart - -IPC_ENUM_TRAITS(media::AudioCodec) -IPC_ENUM_TRAITS(media::MediaPlayerTizen::ReadyState) -IPC_ENUM_TRAITS(media::MediaPlayerTizen::NetworkState) -IPC_ENUM_TRAITS(media::DemuxerStream::Status) -IPC_ENUM_TRAITS(media::DemuxerStream::Type) -IPC_ENUM_TRAITS(media::VideoCodec) -IPC_ENUM_TRAITS(MediaPlayerHostMsg_Initialize_Type) - -IPC_STRUCT_TRAITS_BEGIN(media::DemuxerConfigs) - IPC_STRUCT_TRAITS_MEMBER(audio_codec) - IPC_STRUCT_TRAITS_MEMBER(audio_channels) - IPC_STRUCT_TRAITS_MEMBER(audio_sampling_rate) - IPC_STRUCT_TRAITS_MEMBER(is_audio_encrypted) - IPC_STRUCT_TRAITS_MEMBER(audio_extra_data) - - IPC_STRUCT_TRAITS_MEMBER(video_codec) - IPC_STRUCT_TRAITS_MEMBER(video_size) - IPC_STRUCT_TRAITS_MEMBER(is_video_encrypted) - IPC_STRUCT_TRAITS_MEMBER(video_extra_data) - - IPC_STRUCT_TRAITS_MEMBER(duration_ms) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(media::DemuxedBufferMetaData) - IPC_STRUCT_TRAITS_MEMBER(size) - IPC_STRUCT_TRAITS_MEMBER(end_of_stream) - IPC_STRUCT_TRAITS_MEMBER(timestamp) - IPC_STRUCT_TRAITS_MEMBER(time_duration) - IPC_STRUCT_TRAITS_MEMBER(type) - IPC_STRUCT_TRAITS_MEMBER(status) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(media::SubsampleEntry) - IPC_STRUCT_TRAITS_MEMBER(clear_bytes) - IPC_STRUCT_TRAITS_MEMBER(cypher_bytes) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(media::MediaPlayerTizen::TimeRanges) - IPC_STRUCT_TRAITS_MEMBER(start) - IPC_STRUCT_TRAITS_MEMBER(end) -IPC_STRUCT_TRAITS_END() - -// Initialize Gst player. -IPC_MESSAGE_ROUTED5(MediaPlayerGstHostMsg_Init, - int /* player_id */, - MediaPlayerHostMsg_Initialize_Type /* type */, - GURL /* URL */, - double /* volume */, - int /* demuxer client id */) - -// Deinitialize Gst player. -IPC_MESSAGE_ROUTED1(MediaPlayerGstHostMsg_DeInit, - int /* player_id */) - -// Start playback. -IPC_MESSAGE_ROUTED1(MediaPlayerGstHostMsg_Play, - int /* player_id */) - -// Pause playback. -IPC_MESSAGE_ROUTED1(MediaPlayerGstHostMsg_Pause, - int /* player_id */) - -// Set volume. -IPC_MESSAGE_ROUTED2(MediaPlayerGstHostMsg_SetVolume, - int /* player_id */, - double /* volume */) - -// Set playback rate. -IPC_MESSAGE_ROUTED2(MediaPlayerGstHostMsg_SetRate, - int /* player_id */, - double /* rate */) - -// Playback duration. -IPC_MESSAGE_ROUTED2(MediaPlayerGstMsg_DurationChanged, - int /* player_id */, - double /* time */) - -// Current duration. -IPC_MESSAGE_ROUTED2(MediaPlayerGstMsg_TimeUpdate, - int /* player_id */, - double /* time */) - -// Pause state. -IPC_MESSAGE_ROUTED2(MediaPlayerGstMsg_OnPauseStateChange, - int /* player_id */, - bool /* state */) - -// Seek state. -IPC_MESSAGE_ROUTED2(MediaPlayerGstMsg_OnSeekStateChange, - int /* player_id */, - bool /* state */) - -// Current buffer range. -IPC_MESSAGE_ROUTED2(MediaPlayerGstMsg_BufferUpdate, - int /* player_id */, - std::vector /*buffer_range*/) - -// Playback completed. -IPC_MESSAGE_ROUTED1(MediaPlayerGstMsg_TimeChanged, - int /* player_id */) - -// Ready state change. -IPC_MESSAGE_ROUTED2(MediaPlayerGstMsg_ReadyStateChange, - int /* player_id */, - media::MediaPlayerTizen::ReadyState /* state */) - -// Network state change. -IPC_MESSAGE_ROUTED2(MediaPlayerGstMsg_NetworkStateChange, - int /* player_id */, - media::MediaPlayerTizen::NetworkState /* state */) - -// Gst media data has changed. -IPC_MESSAGE_ROUTED5(MediaPlayerGstMsg_MediaDataChanged, - int /* player_id */, - int /* format */, - int /* height */, - int /* width */, - int /* media */) - -// On new frame available. -IPC_MESSAGE_ROUTED4(MediaPlayerGstMsg_NewFrameAvailable, - int /* player_id */, - base::SharedMemoryHandle /* Handle */, - uint32 /* length */, - base::TimeDelta /* time stamp */) - -#ifdef OS_TIZEN -IPC_MESSAGE_ROUTED3(MediaPlayerGstMsg_PlatformSurfaceUpdated, - int /* player_id */, - int /* pixmap_id */, - base::TimeDelta /* time stamp */) -#endif - -// Seek. -IPC_MESSAGE_ROUTED2(MediaPlayerGstHostMsg_Seek, - int /* player_id */, - double /* time */) - -// For MSE internal seek request. -IPC_MESSAGE_ROUTED2(MediaPlayerGstMsg_SeekRequest, - int /* player_id */, - double /* time_to_seek */) - -// Sent after the renderer demuxer has seeked. -IPC_MESSAGE_CONTROL2(MediaPlayerGstHostMsg_DemuxerSeekDone, - int /* demuxer_client_id */, - base::TimeDelta /* actual_browser_seek_time */) - -// Inform the media source player that the demuxer is ready. -IPC_MESSAGE_CONTROL2(MediaPlayerGstHostMsg_DemuxerReady, - int /* demuxer_client_id */, - media::DemuxerConfigs /* configs */) - -// Sent when the data was read from the ChunkDemuxer. -IPC_MESSAGE_CONTROL3(MediaPlayerGstHostMsg_ReadFromDemuxerAck, - int /* demuxer_client_id */, - base::SharedMemoryHandle /* Handle */, - media::DemuxedBufferMetaData /* meta data of buffer*/) - -// Sent when the data was read from the ChunkDemuxer. -IPC_MESSAGE_CONTROL2(MediaPlayerGstHostMsg_BufferMetaDataAck, - int /* demuxer_client_id */, - media::DemuxedBufferMetaData /* meta data of buffer*/) - -// Inform the media source player of changed media duration from demuxer. -IPC_MESSAGE_CONTROL2(MediaPlayerGstHostMsg_DurationChanged, - int /* demuxer_client_id */, - base::TimeDelta /* duration */) - -// The player needs new config data -IPC_MESSAGE_CONTROL1(MediaPlayerGstMsg_MediaConfigRequest, - int /* demuxer_client_id */) - -// The media source player reads data from demuxer -IPC_MESSAGE_CONTROL2(MediaPlayerGstMsg_ReadFromDemuxer, - int /* demuxer_client_id */, - media::DemuxerStream::Type /* type */) - -// Requests renderer demuxer seek. -IPC_MESSAGE_CONTROL2(MediaPlayerGstMsg_DemuxerSeekRequest, - int /* demuxer_client_id */, - base::TimeDelta /* time_to_seek */) diff --git a/tizen_src/impl/content/renderer/media/tizen/audio_decoder_gstreamer.cc b/tizen_src/impl/content/renderer/media/tizen/audio_decoder_gstreamer.cc deleted file mode 100644 index 4307899cbb33..000000000000 --- a/tizen_src/impl/content/renderer/media/tizen/audio_decoder_gstreamer.cc +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/renderer/media/tizen/audio_decoder_gstreamer.h" - -#include "base/basictypes.h" -#include "base/memory/shared_memory.h" -#include "base/posix/eintr_wrapper.h" -#include "base/process/process.h" -#include "base/strings/string_util.h" -#include "base/time/time.h" -#include "common/render_messages_efl.h" -#include "media/base/audio_bus.h" -#include "media/base/limits.h" -#include "public/platform/Platform.h" -#include "third_party/WebKit/public/platform/WebAudioBus.h" -#include "media/base/tizen/webaudio_media_codec_info_tizen.h" - -namespace content { -//This class is similar as AudioDecoderIO class of Android defined -//in src/content/renderer/media/android/audio_decoder_android.cc -class AudioDecoderIO { - public: - AudioDecoderIO(const char* data, size_t data_size); - ~AudioDecoderIO(); - bool ShareEncodedToProcess(base::SharedMemoryHandle* handle); - - // Returns true if AudioDecoderIO was successfully created. - bool IsValid() const; - - int read_fd() const { return read_fd_; } - int write_fd() const { return write_fd_; } - - private: - // Shared memory that will hold the encoded audio data. This is - // used by MediaCodec for decoding. - base::SharedMemory encoded_shared_memory_; - - // A pipe used to communicate with MediaCodec. MediaCodec owns - // write_fd_ and writes to it. - int read_fd_; - int write_fd_; - - DISALLOW_COPY_AND_ASSIGN(AudioDecoderIO); -}; - -AudioDecoderIO::AudioDecoderIO(const char* data, size_t data_size) - : read_fd_(-1), - write_fd_(-1) { - - if (!data || !data_size || data_size > 0x80000000) - return; - - // Create the shared memory and copy our data to it so that - // MediaCodec can access it. - if(!encoded_shared_memory_.CreateAndMapAnonymous(data_size)) { - LOG(ERROR) << __FUNCTION__ << " Creation of shared memory failed"; - return; - } - - if (!encoded_shared_memory_.memory()) - return; - - memcpy(encoded_shared_memory_.memory(), data, data_size); - - // Create a pipe for reading/writing the decoded PCM data - int pipefd[2]; - - if (pipe(pipefd)) { - LOG(INFO) <<" Pipe is already created"; - return; - } - - read_fd_ = pipefd[0]; - write_fd_ = pipefd[1]; -} - -AudioDecoderIO::~AudioDecoderIO() { - // Close the read end of the pipe. The write end should have been - // closed by MediaCodec. - if (read_fd_ >= 0 && close(read_fd_)) { - LOG(WARNING) << "Cannot close read fd " << read_fd_ - << ": " << strerror(errno); - } -} - -bool AudioDecoderIO::IsValid() const { - return read_fd_ >= 0 && write_fd_ >= 0 && - encoded_shared_memory_.memory(); -} - -bool AudioDecoderIO::ShareEncodedToProcess(base::SharedMemoryHandle* handle) { - return encoded_shared_memory_.ShareToProcess(base::GetCurrentProcessHandle(), - handle); -} - -static float ConvertSampleToFloat(int16_t sample) { - const float kMaxScale = 1.0f / std::numeric_limits::max(); - const float kMinScale = -1.0f / std::numeric_limits::min(); - - return sample * (sample < 0 ? kMinScale : kMaxScale); -} - -static void CopyPcmDataToBus(int input_fd, - blink::WebAudioBus* destination_bus, - size_t num_of_frames, - unsigned number_of_channels, - double file_sample_rate) { - - int16_t pipe_data[PIPE_BUF / sizeof(int16_t)]; - ssize_t nread; - std::vector decoded_samples; - - while ((nread = HANDLE_EINTR(read(input_fd, pipe_data, sizeof(pipe_data)))) > 0) { - size_t samples_in_pipe = nread / sizeof(int16_t); - - if (decoded_samples.size() + samples_in_pipe > decoded_samples.capacity()) { - decoded_samples.reserve(std::max(samples_in_pipe, - 2 * decoded_samples.capacity())); - } - std::copy(pipe_data, - pipe_data + samples_in_pipe, - back_inserter(decoded_samples)); - } - - size_t number_of_samples = decoded_samples.size(); - size_t number_of_frames = decoded_samples.size() / number_of_channels; - size_t decoded_frames = 0; - - destination_bus->initialize(number_of_channels, - number_of_frames, - file_sample_rate); - - for (size_t m = 0; m < number_of_samples; m += number_of_channels) { - for (size_t k = 0; k < number_of_channels; ++k) { - int16_t sample = decoded_samples[m + k]; - destination_bus->channelData(k)[decoded_frames] = - ConvertSampleToFloat(sample); - } - ++decoded_frames; - } - - if (decoded_frames < number_of_frames) - destination_bus->resizeSmaller(decoded_frames); -} - -static void BufferAndCopyPcmDataToBus(int input_fd, - blink::WebAudioBus* destination_bus, - unsigned number_of_channels, - double file_sample_rate) { - int16_t pipe_data[PIPE_BUF / sizeof(int16_t)]; - std::vector decoded_samples; - ssize_t nread; - - while ((nread = HANDLE_EINTR(read(input_fd, pipe_data, sizeof(pipe_data)))) > 0) { - size_t samples_in_pipe = nread / sizeof(int16_t); - if (decoded_samples.size() + samples_in_pipe > decoded_samples.capacity()) { - decoded_samples.reserve(std::max(samples_in_pipe, - 2 * decoded_samples.capacity())); - } - std::copy(pipe_data, - pipe_data + samples_in_pipe, - back_inserter(decoded_samples)); - } - - // Convert the samples and save them in the audio bus. - size_t number_of_samples = decoded_samples.size(); - size_t number_of_frames = decoded_samples.size() / number_of_channels; - size_t decoded_frames = 0; - - destination_bus->initialize(number_of_channels, - number_of_frames, - file_sample_rate); - - for (size_t m = 0; m < number_of_samples; m += number_of_channels) { - for (size_t k = 0; k < number_of_channels; ++k) { - int16_t sample = decoded_samples[m + k]; - destination_bus->channelData(k)[decoded_frames] = - ConvertSampleToFloat(sample); - } - ++decoded_frames; - } - - // number_of_frames is only an estimate. Resize the buffer with the - // actual number of received frames. - if (decoded_frames < number_of_frames) - destination_bus->resizeSmaller(decoded_frames); -} - -// Decode in-memory audio file data. -bool DecodeAudioFileData(blink::WebAudioBus* destination_bus, - const char* data, - size_t data_size, - scoped_refptr sender) { - AudioDecoderIO audio_decoder(data, data_size); - - if (!audio_decoder.IsValid()) { - LOG(ERROR) << "Invalid audio_decoder"; - return false; - } - - base::SharedMemoryHandle encoded_data_handle; - audio_decoder.ShareEncodedToProcess(&encoded_data_handle); - base::FileDescriptor fd(audio_decoder.write_fd(), true); - - // Start Decoding in the browser which will read from - // encoded_data_handle for our shared memory and write the decoded - // PCM samples (16-bit integer) to our pipe. - - sender->Send(new EflViewHostMsg_GstWebAudioDecode(encoded_data_handle, fd, data_size)); - - int input_fd = audio_decoder.read_fd(); - struct media::WebAudioMediaCodecInfoTizen info; - - ssize_t nread = HANDLE_EINTR(read(input_fd, &info, sizeof(info))); - - if (nread != sizeof(info)) { - LOG(ERROR) << "Read Failed"; - return false; - } - - unsigned number_of_channels = info.channel_count; - double file_sample_rate = static_cast(info.sample_rate); - size_t number_of_frames = info.number_of_frames; - - // Sanity checks - if (!number_of_channels || - number_of_channels > media::limits::kMaxChannels || - file_sample_rate < media::limits::kMinSampleRate || - file_sample_rate > media::limits::kMaxSampleRate) { - return false; - } - - if (number_of_frames > 0) { - CopyPcmDataToBus(input_fd, - destination_bus, - number_of_frames, - number_of_channels, - file_sample_rate); - } else { - BufferAndCopyPcmDataToBus(input_fd, - destination_bus, - number_of_channels, - file_sample_rate); - } - - return true; -} - -} // namespace content diff --git a/tizen_src/impl/content/renderer/media/tizen/audio_decoder_gstreamer.h b/tizen_src/impl/content/renderer/media/tizen/audio_decoder_gstreamer.h deleted file mode 100644 index c937ee7b18ee..000000000000 --- a/tizen_src/impl/content/renderer/media/tizen/audio_decoder_gstreamer.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_RENDERER_MEDIA_TIZEN_AUDIO_DECODER_GSTREAMER_H_ -#define CONTENT_RENDERER_MEDIA_TIZEN_AUDIO_DECODER_GSTREAMER_H_ - -#include "content/renderer/media/android/audio_decoder_android.h" - -#endif // CONTENT_RENDERER_MEDIA_TIZEN_AUDIO_DECODER_GSTREAMER_H_ \ No newline at end of file diff --git a/tizen_src/impl/content/renderer/media/tizen/media_source_delegate_tizen.cc b/tizen_src/impl/content/renderer/media/tizen/media_source_delegate_tizen.cc deleted file mode 100644 index 8a14751fdb73..000000000000 --- a/tizen_src/impl/content/renderer/media/tizen/media_source_delegate_tizen.cc +++ /dev/null @@ -1,514 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/renderer/media/tizen/media_source_delegate_tizen.h" - -#include "base/process/process.h" -#include "media/base/bind_to_current_loop.h" -#include "media/base/media_log.h" -#include "media/base/tizen/demuxer_stream_player_params_tizen.h" -#include "media/blink/webmediaplayer_util.h" -#include "media/blink/webmediasource_impl.h" -#include "media/filters/chunk_demuxer.h" -#include "media/filters/decrypting_demuxer_stream.h" -#include "third_party/WebKit/public/web/WebRuntimeFeatures.h" - -namespace content { - -static void LogMediaSourceError( - const scoped_refptr& media_log, - const std::string& error) { - media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error)); -} - -MediaSourceDelegateTizen::MediaSourceDelegateTizen( - RendererDemuxerTizen* demuxer_client, - int demuxer_client_id, - const scoped_refptr& media_task_runner, - media::MediaLog* media_log) - : main_loop_(base::MessageLoopProxy::current()), - main_weak_factory_(this), - main_weak_this_(main_weak_factory_.GetWeakPtr()), - media_task_runner_(media_task_runner), - media_weak_factory_(this), - demuxer_client_(demuxer_client), - demuxer_client_id_(demuxer_client_id), - media_log_(media_log), - audio_stream_(NULL), - video_stream_(NULL), - seek_time_(media::kNoTimestamp()), - pending_seek_(false), - is_seeking_(false), - seeking_pending_seek_(false), - is_demuxer_seek_done_(false), - pending_seek_time_(media::kNoTimestamp()), - is_audio_read_fired_(false), - is_video_read_fired_(false), - is_demuxer_ready_(false), - shared_memory_size_(0) { - VLOG(1) << "MediaSourceDelegateTizen::" << __FUNCTION__ - << ": Demuxer Client Id = " << demuxer_client_id_; - DCHECK(!chunk_demuxer_); -} - -MediaSourceDelegateTizen::~MediaSourceDelegateTizen() { - DCHECK(main_loop_->BelongsToCurrentThread()); - DCHECK(!chunk_demuxer_); - DCHECK(!audio_stream_); - DCHECK(!video_stream_); - DCHECK(!audio_decrypting_demuxer_stream_); - DCHECK(!video_decrypting_demuxer_stream_); -} - -void MediaSourceDelegateTizen::InitializeMediaSource( - const MediaSourceOpenedCB& media_source_opened_cb, - const media::Demuxer::NeedKeyCB& need_key_cb, - const media::SetDecryptorReadyCB& set_decryptor_ready_cb, - const UpdateNetworkStateCB& update_network_state_cb, - const DurationChangeCB& duration_change_cb) { - DCHECK(main_loop_->BelongsToCurrentThread()); - DCHECK(!media_source_opened_cb.is_null()); - media_source_opened_cb_ = media_source_opened_cb; - need_key_cb_ = need_key_cb; - set_decryptor_ready_cb_ = set_decryptor_ready_cb; - update_network_state_cb_ = media::BindToCurrentLoop(update_network_state_cb); - duration_change_cb_ = duration_change_cb; - - chunk_demuxer_.reset(new media::ChunkDemuxer( - media::BindToCurrentLoop(base::Bind( - &MediaSourceDelegateTizen::OnDemuxerOpened, main_weak_this_)), - media::BindToCurrentLoop(base::Bind( - &MediaSourceDelegateTizen::OnNeedKey, main_weak_this_)), - base::Bind(&LogMediaSourceError, media_log_), - false)); - - media_task_runner_->PostTask(FROM_HERE, - base::Bind(&MediaSourceDelegateTizen::InitializeDemuxer, - base::Unretained(this))); -} - -void MediaSourceDelegateTizen::InitializeDemuxer() { - DCHECK(media_task_runner_->BelongsToCurrentThread()); - demuxer_client_->AddDelegate(demuxer_client_id_, this); - chunk_demuxer_->Initialize( - this, - base::Bind(&MediaSourceDelegateTizen::OnDemuxerInitDone, - media_weak_factory_.GetWeakPtr()), - false); -} - -void MediaSourceDelegateTizen::OnNeedKey( - const std::string& type, - const std::vector& init_data) { - DCHECK(main_loop_->BelongsToCurrentThread()); - if (need_key_cb_.is_null()) { - return; - } - need_key_cb_.Run(type, init_data); -} - -void MediaSourceDelegateTizen::OnDemuxerOpened() { - DCHECK(main_loop_->BelongsToCurrentThread()); - if (media_source_opened_cb_.is_null()) - return; - media_source_opened_cb_.Run(new media::WebMediaSourceImpl( - chunk_demuxer_.get(), base::Bind(&LogMediaSourceError, media_log_))); -} - -void MediaSourceDelegateTizen::OnDemuxerError( - media::PipelineStatus status) { - if (status != media::PIPELINE_OK && !update_network_state_cb_.is_null()) - update_network_state_cb_.Run(PipelineErrorToNetworkState(status)); -} - -void MediaSourceDelegateTizen::OnDemuxerInitDone( - media::PipelineStatus status) { - DCHECK(media_task_runner_->BelongsToCurrentThread()); - DCHECK(chunk_demuxer_); - if (status != media::PIPELINE_OK) { - OnDemuxerError(status); - return; - } - audio_stream_ = chunk_demuxer_->GetStream(media::DemuxerStream::AUDIO); - video_stream_ = chunk_demuxer_->GetStream(media::DemuxerStream::VIDEO); - if (audio_stream_ && audio_stream_->audio_decoder_config().is_encrypted() && - !set_decryptor_ready_cb_.is_null()) { - InitAudioDecryptingDemuxerStream(); - return; - } - if (video_stream_ && video_stream_->video_decoder_config().is_encrypted() && - !set_decryptor_ready_cb_.is_null()) { - InitVideoDecryptingDemuxerStream(); - return; - } - // Notify demuxer ready when both streams are not encrypted. - is_demuxer_ready_ = true; - NotifyDemuxerReady(); -} - -void MediaSourceDelegateTizen::InitAudioDecryptingDemuxerStream() { - DCHECK(media_task_runner_->BelongsToCurrentThread()); - audio_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream( - media_task_runner_, set_decryptor_ready_cb_)); - - audio_decrypting_demuxer_stream_->Initialize( - audio_stream_, - base::Bind(&MediaSourceDelegateTizen::OnAudioDecryptingDemuxerStreamInitDone, - media_weak_factory_.GetWeakPtr())); -} - -void MediaSourceDelegateTizen::InitVideoDecryptingDemuxerStream() { - DCHECK(media_task_runner_->BelongsToCurrentThread()); - - video_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream( - media_task_runner_, set_decryptor_ready_cb_)); - - video_decrypting_demuxer_stream_->Initialize( - video_stream_, - base::Bind(&MediaSourceDelegateTizen::OnVideoDecryptingDemuxerStreamInitDone, - media_weak_factory_.GetWeakPtr())); -} - - -void MediaSourceDelegateTizen::OnAudioDecryptingDemuxerStreamInitDone( - media::PipelineStatus status) { - DCHECK(media_task_runner_->BelongsToCurrentThread()); - DCHECK(chunk_demuxer_); - - if (status != media::PIPELINE_OK) - audio_decrypting_demuxer_stream_.reset(); - else - audio_stream_ = audio_decrypting_demuxer_stream_.get(); - - if (video_stream_ && video_stream_->video_decoder_config().is_encrypted()) { - InitVideoDecryptingDemuxerStream(); - return; - } - - // Try to notify demuxer ready when audio DDS initialization finished and - // video is not encrypted. - is_demuxer_ready_ = true; - NotifyDemuxerReady(); -} - -void MediaSourceDelegateTizen::OnVideoDecryptingDemuxerStreamInitDone( - media::PipelineStatus status) { - DCHECK(media_task_runner_->BelongsToCurrentThread()); - DCHECK(chunk_demuxer_); - - if (status != media::PIPELINE_OK) - video_decrypting_demuxer_stream_.reset(); - else - video_stream_ = video_decrypting_demuxer_stream_.get(); - - // Try to notify demuxer ready when video DDS initialization finished. - is_demuxer_ready_ = true; - NotifyDemuxerReady(); -} - -void MediaSourceDelegateTizen::NotifyDemuxerReady() { - DCHECK(media_task_runner_->BelongsToCurrentThread()); - DCHECK(is_demuxer_ready_); - - scoped_ptr configs(new media::DemuxerConfigs()); - if (audio_stream_) { - media::AudioDecoderConfig audio_config = - audio_stream_->audio_decoder_config(); - configs->audio_codec = audio_config.codec(); - configs->audio_channels = - media::ChannelLayoutToChannelCount(audio_config.channel_layout()); - configs->audio_sampling_rate = audio_config.samples_per_second(); - configs->is_audio_encrypted = audio_config.is_encrypted(); - configs->audio_extra_data = std::vector(audio_config.extra_data(), - audio_config.extra_data() + audio_config.extra_data_size()); - } - if (video_stream_) { - media::VideoDecoderConfig video_config = - video_stream_->video_decoder_config(); - configs->video_codec = video_config.codec(); - configs->video_size = video_config.natural_size(); - configs->is_video_encrypted = video_config.is_encrypted(); - configs->video_extra_data = std::vector(video_config.extra_data(), - video_config.extra_data() + video_config.extra_data_size()); - } - if (demuxer_client_) { - demuxer_client_->DemuxerReady(demuxer_client_id_, *configs); - } -} - -void MediaSourceDelegateTizen::OnReadFromDemuxer( - media::DemuxerStream::Type type) { - DCHECK(media_task_runner_->BelongsToCurrentThread()); - - if (is_seeking_) - return; - - if ((type == media::DemuxerStream::AUDIO) && audio_stream_ - && !is_audio_read_fired_) { - is_audio_read_fired_ = true; - audio_stream_->Read(base::Bind( - &MediaSourceDelegateTizen::OnBufferReady, - media_weak_factory_.GetWeakPtr() , type)); - } - - if ((type == media::DemuxerStream::VIDEO) && video_stream_ - && !is_video_read_fired_) { - is_video_read_fired_ = true; - video_stream_->Read(base::Bind( - &MediaSourceDelegateTizen::OnBufferReady, - media_weak_factory_.GetWeakPtr() , type)); - } -} - -void MediaSourceDelegateTizen::Stop(const base::Closure& stop_cb) { - DCHECK(main_loop_->BelongsToCurrentThread()); - VLOG(1) << "MediaSourceDelegateTizen::" << __FUNCTION__ - << ": Demuxer Client Id = " << demuxer_client_id_; - - if (!chunk_demuxer_) { - DCHECK(!demuxer_client_); - return; - } - - duration_change_cb_.Reset(); - update_network_state_cb_.Reset(); - media_source_opened_cb_.Reset(); - - main_weak_factory_.InvalidateWeakPtrs(); - DCHECK(!main_weak_factory_.HasWeakPtrs()); - - // 1. shutdown demuxer. - // 2. On media thread, call stop demuxer. - // 3. On callback, post message and self destory. - chunk_demuxer_->Shutdown(); - media_task_runner_->PostTask( - FROM_HERE, - base::Bind(&MediaSourceDelegateTizen::StopDemuxer, - base::Unretained(this), - stop_cb)); -} - -void MediaSourceDelegateTizen::StopDemuxer(const base::Closure& stop_cb) { - DCHECK(media_task_runner_->BelongsToCurrentThread()); - DCHECK(chunk_demuxer_); - - demuxer_client_->RemoveDelegate(demuxer_client_id_); - demuxer_client_ = NULL; - audio_stream_ = NULL; - video_stream_ = NULL; - audio_decrypting_demuxer_stream_.reset(); - video_decrypting_demuxer_stream_.reset(); - - media_weak_factory_.InvalidateWeakPtrs(); - DCHECK(!media_weak_factory_.HasWeakPtrs()); - - chunk_demuxer_->Stop(); - chunk_demuxer_.reset(); - - stop_cb.Run(); -} - -void MediaSourceDelegateTizen::OnMediaConfigRequest() { - NotifyDemuxerReady(); -} - -void MediaSourceDelegateTizen::SeekInternal( - const base::TimeDelta& seek_time) { - DCHECK(media_task_runner_->BelongsToCurrentThread()); - chunk_demuxer_->Seek(seek_time, base::Bind( - &MediaSourceDelegateTizen::OnDemuxerSeekDone, - media_weak_factory_.GetWeakPtr())); -} - -void MediaSourceDelegateTizen::OnBufferReady( - media::DemuxerStream::Type type, - media::DemuxerStream::Status status, - const scoped_refptr& buffer) { - - scoped_ptr meta_data( - new media::DemuxedBufferMetaData()); - meta_data->status = status; - meta_data->type = type; - - if (type == media::DemuxerStream::AUDIO) - is_audio_read_fired_ = false; - if (type == media::DemuxerStream::VIDEO) - is_video_read_fired_ = false; - - switch (status) { - case media::DemuxerStream::kAborted: - LOG (ERROR) << "[RENDER] : DemuxerStream::kAborted"; - break; - - case media::DemuxerStream::kConfigChanged: - VLOG(1) << "[RENDER] : DemuxerStream::kConfigChanged"; - NotifyDemuxerReady(); - break; - - case media::DemuxerStream::kOk: - if (buffer.get()->end_of_stream()) { - VLOG(1) << "[RENDER] : DemuxerStream::kOk but |end_of_stream|"; - meta_data->end_of_stream = true; - break; - } - shared_memory_size_ = buffer.get()->data_size(); - if (!shared_memory_.CreateAndMapAnonymous(shared_memory_size_)) { - LOG (ERROR) << "Shared Memory creation failed."; - return; - } - if (!shared_memory_.ShareToProcess(base::Process::Current().Handle(), - &foreign_memory_handle_)) { - LOG (ERROR) << "Shared Memory handle could not be obtained"; - shared_memory_.Close(); - return; - } - memcpy(shared_memory_.memory(), (void*)buffer.get()->writable_data(), - shared_memory_size_); - meta_data->timestamp = buffer.get()->timestamp(); - meta_data->time_duration = buffer.get()->duration(); - if (demuxer_client_) { - meta_data->size = shared_memory_size_; - demuxer_client_->ReadFromDemuxerAck( - demuxer_client_id_, foreign_memory_handle_, *meta_data); - } - shared_memory_.Close(); - return; - break; - default: - NOTREACHED(); - } - - if (demuxer_client_) - demuxer_client_->BufferMetaDataAck(demuxer_client_id_, *meta_data); -} - -void MediaSourceDelegateTizen::StartWaitingForSeek( - const base::TimeDelta& seek_time) { - DCHECK(main_loop_->BelongsToCurrentThread()); - - if (!chunk_demuxer_) - return; - // Called from |webmediaplayertizen| only. - is_demuxer_seek_done_ = false; - seeking_pending_seek_ = false; - is_seeking_ = true; - chunk_demuxer_->StartWaitingForSeek(seek_time); -} - -void MediaSourceDelegateTizen::CancelPendingSeek( - const base::TimeDelta& seek_time) { - DCHECK(main_loop_->BelongsToCurrentThread()); - if (!chunk_demuxer_) - return; - is_seeking_ = true; - pending_seek_ = true; - pending_seek_time_ = seek_time; - - if (is_demuxer_seek_done_) { - // Since we already requested gstreamer to seek. And there are no pending - // seeks in |chunk_demuxer|. Cancelling pending seek makes no sense. - // - // This block will handle when |gstreamer| is seeking and new seek came in - // between. - VLOG(1) << "No need to CancelPendingSeek"; - is_demuxer_seek_done_ = false; - pending_seek_ = false; - chunk_demuxer_->StartWaitingForSeek(seek_time); - StartSeek(seek_time, true); - return; - } - - chunk_demuxer_->CancelPendingSeek(seek_time); -} - -void MediaSourceDelegateTizen::StartSeek( - const base::TimeDelta& seek_time, - bool is_seeking_pending_seek) { - DCHECK(media_task_runner_->BelongsToCurrentThread()); - - VLOG(1)<< "MediaSourceDelegateTizen::" << __FUNCTION__ - << " : " << seek_time.InSecondsF(); - if (!chunk_demuxer_) - return; - is_seeking_ = true; - is_demuxer_seek_done_ = false; - if (is_seeking_pending_seek) - seeking_pending_seek_ = is_seeking_pending_seek; - else if (seeking_pending_seek_) { - VLOG(1)<< "Ignoring seek request from Gstreamer"; - return; - } - seek_time_ = seek_time; - SeekInternal(seek_time); -} - -void MediaSourceDelegateTizen::OnDemuxerSeekDone( - media::PipelineStatus status) { - DCHECK(media_task_runner_->BelongsToCurrentThread()); - if (status != media::PIPELINE_OK) { - OnDemuxerError(status); - return; - } - if (pending_seek_) { - pending_seek_ = false; - StartSeek(pending_seek_time_, true); - seek_time_ = pending_seek_time_; - } else { - VLOG(1) << "Actual time that Gstreamer seeks : " - << seek_time_.InMilliseconds(); - seeking_pending_seek_ = false; - is_seeking_ = false; - is_demuxer_seek_done_ = true; - demuxer_client_->DemuxerSeekDone(demuxer_client_id_, seek_time_); - } - ResetAudioDecryptingDemuxerStream(); -} - -void MediaSourceDelegateTizen::ResetAudioDecryptingDemuxerStream() { - DCHECK(media_task_runner_->BelongsToCurrentThread()); - if (audio_decrypting_demuxer_stream_) { - audio_decrypting_demuxer_stream_->Reset( - base::Bind(&MediaSourceDelegateTizen::ResetVideoDecryptingDemuxerStream, - media_weak_factory_.GetWeakPtr())); - return; - } - ResetVideoDecryptingDemuxerStream(); -} - -void MediaSourceDelegateTizen::ResetVideoDecryptingDemuxerStream() { - DCHECK(media_task_runner_->BelongsToCurrentThread()); - if (video_decrypting_demuxer_stream_) { - video_decrypting_demuxer_stream_->Reset(base::Bind( - &MediaSourceDelegateTizen::FinishResettingDecryptingDemuxerStreams, - media_weak_factory_.GetWeakPtr())); - return; - } - FinishResettingDecryptingDemuxerStreams(); -} - -void MediaSourceDelegateTizen::FinishResettingDecryptingDemuxerStreams() { - DCHECK(media_task_runner_->BelongsToCurrentThread()); - DCHECK(is_seeking_); - is_seeking_ = false; - demuxer_client_->DemuxerSeekDone(demuxer_client_id_, seek_time_); -} - -void MediaSourceDelegateTizen::SetDuration(base::TimeDelta duration) { - DCHECK(main_loop_->BelongsToCurrentThread()); - main_loop_->PostTask(FROM_HERE, base::Bind( - &MediaSourceDelegateTizen::OnDurationChanged, - main_weak_this_, duration)); -} - -void MediaSourceDelegateTizen::OnDurationChanged( - const base::TimeDelta& duration) { - DCHECK(main_loop_->BelongsToCurrentThread()); - if (demuxer_client_) - demuxer_client_->DurationChanged(demuxer_client_id_, duration); - - if (!duration_change_cb_.is_null()) - duration_change_cb_.Run(duration.InSecondsF()); -} - -} // namespace content diff --git a/tizen_src/impl/content/renderer/media/tizen/media_source_delegate_tizen.h b/tizen_src/impl/content/renderer/media/tizen/media_source_delegate_tizen.h deleted file mode 100644 index 87277712be05..000000000000 --- a/tizen_src/impl/content/renderer/media/tizen/media_source_delegate_tizen.h +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_RENDERER_MEDIA_TIZEN_MEDIA_SOURCE_DELEGATE_TIZEN_H_ -#define CONTENT_RENDERER_MEDIA_TIZEN_MEDIA_SOURCE_DELEGATE_TIZEN_H_ - -#include "content/renderer/media/tizen/renderer_demuxer_tizen.h" -#include "media/base/decoder_buffer.h" -#include "media/base/demuxer_stream.h" -#include "media/base/media_keys.h" -#include "media/filters/chunk_demuxer.h" -#include "media/filters/decrypting_demuxer_stream.h" -#include "third_party/WebKit/public/platform/WebMediaPlayer.h" - -namespace content { - -class MediaSourceDelegateTizen - : public media::DemuxerHost { -public: - typedef base::Callback - MediaSourceOpenedCB; - typedef base::Callback - UpdateNetworkStateCB; - typedef base::Callback DurationChangeCB; - - MediaSourceDelegateTizen( - RendererDemuxerTizen* demuxer_client, - int demuxer_client_id, - const scoped_refptr& media_task_runner, - media::MediaLog* media_log); - ~MediaSourceDelegateTizen(); - - //DemuxerHost implementation. - virtual void AddBufferedTimeRange( - base::TimeDelta start, - base::TimeDelta end) override {}; - - // Sets the duration of the media in microseconds. - // Duration may be kInfiniteDuration() if the duration is not known. - virtual void SetDuration(base::TimeDelta duration) override; - - // Stops execution of the pipeline due to a fatal error. Do not call this - // method with PIPELINE_OK. - virtual void OnDemuxerError(media::PipelineStatus error) override; - - // Add |text_stream| to the collection managed by the text renderer. - virtual void AddTextStream( - media::DemuxerStream* text_stream, - const media::TextTrackConfig& config) override {}; - - // Remove |text_stream| from the presentation. - virtual void RemoveTextStream(media::DemuxerStream* text_stream) override {}; - - void InitializeMediaSource( - const MediaSourceOpenedCB& media_source_opened_cb, - const media::Demuxer::NeedKeyCB& need_key_cb, - const media::SetDecryptorReadyCB& set_decryptor_ready_cb, - const UpdateNetworkStateCB& update_network_state_cb, - const DurationChangeCB& duration_change_cb); - - // Called when DemuxerStreamPlayer needs to read data from ChunkDemuxer. - void OnReadFromDemuxer(media::DemuxerStream::Type type); - - // Must be called explicitly before |this| can be destroyed. - void Stop(const base::Closure& stop_cb); - - // In MSE case, calls ChunkDemuxer::StartWaitingForSeek(), sets the - // expectation that a regular seek will be arriving. - void StartWaitingForSeek(const base::TimeDelta& seek_time); - - // Calls ChunkDemuxer::CancelPendingSeek(). Also sets the - // expectation that a regular seek will be arriving. - void CancelPendingSeek(const base::TimeDelta& seek_time); - - // Sets the expectation that a regular seek will be arriving. - void StartSeek( - const base::TimeDelta& seek_time, - bool is_seeking_pending_seek); - - // Callback for ChunkDemuxer::Seek() and callback chain for resetting - // decrypted audio/video streams if present. - // - // Runs on the media thread. - void OnDemuxerSeekDone(media::PipelineStatus status); - - // Called when the player needs the new config data from ChunkDemuxer. - void OnMediaConfigRequest(); - - private: - void OnNeedKey(const std::string& type, const std::vector& init_data); - void OnDemuxerOpened(); - void InitializeDemuxer(); - void OnDemuxerInitDone(media::PipelineStatus status); - - // Stops and clears objects on the media thread. - void StopDemuxer(const base::Closure& stop_cb); - - void NotifyDemuxerReady(); - void OnDurationChanged(const base::TimeDelta& duration); - void OnBufferReady( - media::DemuxerStream::Type type, - media::DemuxerStream::Status status, - const scoped_refptr& buffer); - void SeekInternal(const base::TimeDelta& seek_time); - - // Initializes DecryptingDemuxerStreams if audio/video stream is encrypted. - void InitAudioDecryptingDemuxerStream(); - void InitVideoDecryptingDemuxerStream(); - - // Callbacks for DecryptingDemuxerStream::Initialize(). - void OnAudioDecryptingDemuxerStreamInitDone(media::PipelineStatus status); - void OnVideoDecryptingDemuxerStreamInitDone(media::PipelineStatus status); - - // Runs on the media thread. - void ResetAudioDecryptingDemuxerStream(); - void ResetVideoDecryptingDemuxerStream(); - void FinishResettingDecryptingDemuxerStreams(); - - // Message loop for main renderer thread and corresponding weak pointer. - const scoped_refptr main_loop_; - base::WeakPtrFactory main_weak_factory_; - base::WeakPtr main_weak_this_; - - // Message loop for media thread and corresponding weak pointer. - const scoped_refptr media_task_runner_; - base::WeakPtrFactory media_weak_factory_; - RendererDemuxerTizen* demuxer_client_; - int demuxer_client_id_; - scoped_refptr media_log_; - - MediaSourceOpenedCB media_source_opened_cb_; - UpdateNetworkStateCB update_network_state_cb_; - DurationChangeCB duration_change_cb_; - - scoped_ptr chunk_demuxer_; - media::DemuxerStream* audio_stream_; - media::DemuxerStream* video_stream_; - - media::SetDecryptorReadyCB set_decryptor_ready_cb_; - media::Demuxer::NeedKeyCB need_key_cb_; - scoped_ptr audio_decrypting_demuxer_stream_; - scoped_ptr video_decrypting_demuxer_stream_; - - base::TimeDelta seek_time_; - bool pending_seek_; - bool is_seeking_; - - // Will handle internal seek coming from |MediaSourcePlayerGstreamer| - // if new seek has been fired by |HTMLMediaElement|. - // Always one should seek to latest time and ignore previous seeks. - bool seeking_pending_seek_; - - // Will handle |seek| request coming after |chunk_demuxer| - // has requested |gstreamer| to seek. - bool is_demuxer_seek_done_; - base::TimeDelta pending_seek_time_; - - bool is_audio_read_fired_; - bool is_video_read_fired_; - - bool is_demuxer_ready_; - - uint32 shared_memory_size_; - base::SharedMemory shared_memory_; - base::SharedMemoryHandle foreign_memory_handle_; -}; - -} // namespace content - -#endif // CONTENT_RENDERER_MEDIA_TIZEN_MEDIA_SOURCE_DELEGATE_TIZEN_H_ diff --git a/tizen_src/impl/content/renderer/media/tizen/renderer_demuxer_tizen.cc b/tizen_src/impl/content/renderer/media/tizen/renderer_demuxer_tizen.cc deleted file mode 100644 index 7406988f2824..000000000000 --- a/tizen_src/impl/content/renderer/media/tizen/renderer_demuxer_tizen.cc +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/renderer/media/tizen/renderer_demuxer_tizen.h" - -#include "base/bind.h" -#include "base/message_loop/message_loop.h" -#include "content/child/thread_safe_sender.h" -#include "content/common/media/tizen/media_player_messages_tizen.h" -#include "content/renderer/media/tizen/media_source_delegate_tizen.h" -#include "content/renderer/media/tizen/renderer_media_player_manager_tizen.h" -#include "content/renderer/render_thread_impl.h" - -namespace content { - -RendererDemuxerTizen::RendererDemuxerTizen() - : thread_safe_sender_(RenderThreadImpl::current()->thread_safe_sender()), - media_task_runner_( - RenderThreadImpl::current()->GetMediaThreadTaskRunner()) {} - -RendererDemuxerTizen::~RendererDemuxerTizen() {} - -int RendererDemuxerTizen::GetNextDemuxerClientID() { - // Don't use zero for IDs since it can be interpreted as having no ID. - return next_demuxer_client_id_.GetNext() + 1; -} - -void RendererDemuxerTizen::AddDelegate( - int demuxer_client_id, - MediaSourceDelegateTizen* delegate) { - DCHECK(media_task_runner_->BelongsToCurrentThread()); - delegates_.AddWithID(delegate, demuxer_client_id); -} - -void RendererDemuxerTizen::RemoveDelegate(int demuxer_client_id) { - DCHECK(media_task_runner_->BelongsToCurrentThread()); - delegates_.Remove(demuxer_client_id); -} - -bool RendererDemuxerTizen::OnMessageReceived(const IPC::Message& message) { - switch (message.type()) { - case MediaPlayerGstMsg_ReadFromDemuxer::ID: - case MediaPlayerGstMsg_MediaConfigRequest::ID: - case MediaPlayerGstMsg_DemuxerSeekRequest::ID: - media_task_runner_->PostTask(FROM_HERE, base::Bind( - &RendererDemuxerTizen::DispatchMessage, this, message)); - return true; - } - return false; -} - -void RendererDemuxerTizen::DemuxerReady( - int demuxer_client_id, - const media::DemuxerConfigs& configs) { - thread_safe_sender_->Send(new MediaPlayerGstHostMsg_DemuxerReady( - demuxer_client_id, configs)); -} - -void RendererDemuxerTizen::ReadFromDemuxerAck( - int demuxer_client_id, - base::SharedMemoryHandle foreign_memory_handle, - const media::DemuxedBufferMetaData& meta_data) { - thread_safe_sender_->Send(new MediaPlayerGstHostMsg_ReadFromDemuxerAck( - demuxer_client_id, foreign_memory_handle, meta_data)); -} - -void RendererDemuxerTizen::BufferMetaDataAck( - int demuxer_client_id, - const media::DemuxedBufferMetaData& meta_data) { - thread_safe_sender_->Send(new MediaPlayerGstHostMsg_BufferMetaDataAck( - demuxer_client_id, meta_data)); -} - -void RendererDemuxerTizen::DemuxerSeekDone( - int demuxer_client_id, - const base::TimeDelta& actual_browser_seek_time) { - thread_safe_sender_->Send(new MediaPlayerGstHostMsg_DemuxerSeekDone( - demuxer_client_id, actual_browser_seek_time)); -} - -void RendererDemuxerTizen::DurationChanged(int demuxer_client_id, - const base::TimeDelta& duration) { - thread_safe_sender_->Send(new MediaPlayerGstHostMsg_DurationChanged( - demuxer_client_id, duration)); -} - -void RendererDemuxerTizen::DispatchMessage(const IPC::Message& message) { - IPC_BEGIN_MESSAGE_MAP(RendererDemuxerTizen, message) - IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_ReadFromDemuxer, OnReadFromDemuxer) - IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_MediaConfigRequest, - OnMediaConfigRequest) - IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_DemuxerSeekRequest, - OnDemuxerSeekRequest) - IPC_END_MESSAGE_MAP() -} - -void RendererDemuxerTizen::OnReadFromDemuxer( - int demuxer_client_id, - media::DemuxerStream::Type type) { - MediaSourceDelegateTizen* delegate = delegates_.Lookup(demuxer_client_id); - if (delegate) - delegate->OnReadFromDemuxer(type); -} - -void RendererDemuxerTizen::OnDemuxerSeekRequest( - int demuxer_client_id, - const base::TimeDelta& time_to_seek) { - MediaSourceDelegateTizen* delegate = delegates_.Lookup(demuxer_client_id); - if (delegate) - delegate->StartSeek(time_to_seek, false); -} - -void RendererDemuxerTizen::OnMediaConfigRequest(int demuxer_client_id) { - MediaSourceDelegateTizen* delegate = delegates_.Lookup(demuxer_client_id); - if (delegate) - delegate->OnMediaConfigRequest(); -} - -} // namespace content diff --git a/tizen_src/impl/content/renderer/media/tizen/renderer_demuxer_tizen.h b/tizen_src/impl/content/renderer/media/tizen/renderer_demuxer_tizen.h deleted file mode 100644 index 68958b5f4b0e..000000000000 --- a/tizen_src/impl/content/renderer/media/tizen/renderer_demuxer_tizen.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_RENDERER_MEDIA_TIZEN_RENDERER_DEMUXER_TIZEN_H_ -#define CONTENT_RENDERER_MEDIA_TIZEN_RENDERER_DEMUXER_TIZEN_H_ - -#include "base/atomic_sequence_num.h" -#include "base/id_map.h" -#include "ipc/message_filter.h" -#include "media/base/tizen/demuxer_stream_player_params_tizen.h" - -namespace base { -class SingleThreadTaskRunner; -} - -namespace content { - -class MediaSourceDelegateTizen; -class ThreadSafeSender; - -// Represents the renderer process half of an IPC-based implementation of -// media::DemuxerTizen. -// -// Refer to BrowserDemuxerTizen for the browser process half. -class RendererDemuxerTizen : public IPC::MessageFilter { - public: - RendererDemuxerTizen(); - - // Returns the next available demuxer client ID for use in IPC messages. - // - // Safe to call on any thread. - int GetNextDemuxerClientID(); - - // Associates |delegate| with |demuxer_client_id| for handling incoming IPC - // messages. - // - // Must be called on media thread. - void AddDelegate( - int demuxer_client_id, - MediaSourceDelegateTizen* delegate); - - // Removes the association created by AddDelegate(). - // - // Must be called on media thread. - void RemoveDelegate(int demuxer_client_id); - - // IPC::ChannelProxy::MessageFilter overrides. - virtual bool OnMessageReceived(const IPC::Message& message) override; - - // media::DemuxerTizenClient "implementation". - void DemuxerReady( - int demuxer_client_id, - const media::DemuxerConfigs& configs); - void ReadFromDemuxerAck( - int demuxer_client_id, - base::SharedMemoryHandle foreign_memory_handle, - const media::DemuxedBufferMetaData& meta_data); - void BufferMetaDataAck( - int demuxer_client_id, - const media::DemuxedBufferMetaData& meta_data); - void DemuxerSeekDone( - int demuxer_client_id, - const base::TimeDelta& actual_browser_seek_time); - void DurationChanged(int demuxer_client_id, const base::TimeDelta& duration); - - protected: - friend class base::RefCountedThreadSafe; - virtual ~RendererDemuxerTizen(); - - private: - void DispatchMessage(const IPC::Message& message); - void OnReadFromDemuxer(int demuxer_client_id, - media::DemuxerStream::Type type); - void OnDemuxerSeekRequest(int demuxer_client_id, - const base::TimeDelta& time_to_seek); - void OnMediaConfigRequest(int demuxer_client_id); - - base::AtomicSequenceNumber next_demuxer_client_id_; - - IDMap delegates_; - scoped_refptr thread_safe_sender_; - scoped_refptr media_task_runner_; - - DISALLOW_COPY_AND_ASSIGN(RendererDemuxerTizen); -}; - -} // namespace content - -#endif // CONTENT_RENDERER_MEDIA_TIZEN_RENDERER_DEMUXER_TIZEN_H_ \ No newline at end of file diff --git a/tizen_src/impl/content/renderer/media/tizen/renderer_media_player_manager_tizen.cc b/tizen_src/impl/content/renderer/media/tizen/renderer_media_player_manager_tizen.cc deleted file mode 100644 index f7733fbdb4f7..000000000000 --- a/tizen_src/impl/content/renderer/media/tizen/renderer_media_player_manager_tizen.cc +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/renderer/media/tizen/renderer_media_player_manager_tizen.h" - -#include "base/bind.h" -#include "base/message_loop/message_loop.h" -#include "content/common/media/tizen/media_player_messages_tizen.h" -#include "ui/gfx/rect_f.h" - -namespace content { - -RendererMediaPlayerManagerTizen::RendererMediaPlayerManagerTizen( - RenderFrame* render_frame) - : RenderFrameObserver(render_frame), - next_media_player_id_(0) { -} - -RendererMediaPlayerManagerTizen::~RendererMediaPlayerManagerTizen() { - DCHECK(media_players_.empty()) - << "RendererMediaPlayerManagerTizen is owned by RenderFrameImpl and is " - "destroyed only after all media players are destroyed."; -} - -void RendererMediaPlayerManagerTizen::PausePlayingPlayers() { - std::map::iterator player_it; - for (player_it = media_players_.begin();player_it != media_players_.end();) { - media::WebMediaPlayerTizen* player = player_it->second; - // Element pointed by the iterator can get deleted during the function call - // "player->RequestPause()", hence increment the iterator beforehand - ++player_it; - if (player && !player->paused() && player->hasVideo()) - player->RequestPause(); - } -} - -bool RendererMediaPlayerManagerTizen::OnMessageReceived( - const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(RendererMediaPlayerManagerTizen, message) - IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_MediaDataChanged, OnMediaDataChange) - IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_DurationChanged, OnDurationChange) - IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_TimeUpdate, OnTimeUpdate) - IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_BufferUpdate, OnBufferUpdate) - IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_ReadyStateChange, OnReadyStateChange) - IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_NetworkStateChange, - OnNetworkStateChange) - IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_TimeChanged, OnTimeChanged) - IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_OnPauseStateChange, - OnPauseStateChange) - IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_OnSeekStateChange, OnSeekStateChange) - IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_SeekRequest, OnRequestSeek) - IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_NewFrameAvailable, - OnNewFrameAvailable) -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - IPC_MESSAGE_HANDLER(MediaPlayerGstMsg_PlatformSurfaceUpdated, - OnPlatformSurfaceUpdated) -#endif - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void RendererMediaPlayerManagerTizen::Initialize( - int player_id, - MediaPlayerHostMsg_Initialize_Type type, - const GURL& url, - double volume, - int demuxer_client_id) { - Send(new MediaPlayerGstHostMsg_Init( - routing_id(), player_id, type, url, volume, demuxer_client_id)); -} - -void RendererMediaPlayerManagerTizen::OnMediaDataChange( - int player_id, - int format, - int height, - int width, - int media) { - media::WebMediaPlayerTizen* player = GetMediaPlayer(player_id); - if (player) - player->OnMediaDataChange(format, height, width, media); -} - -void RendererMediaPlayerManagerTizen::OnDurationChange( - int player_id, - double duration) { - media::WebMediaPlayerTizen* player = GetMediaPlayer(player_id); - if (player) - player->OnDurationChange(duration); -} - -void RendererMediaPlayerManagerTizen::OnTimeUpdate( - int player_id, - double current_time) { - media::WebMediaPlayerTizen* player = GetMediaPlayer(player_id); - if (player) - player->OnTimeUpdate(current_time); -} - -void RendererMediaPlayerManagerTizen::OnBufferUpdate( - int player_id, - std::vector buffer_range) { - media::WebMediaPlayerTizen* player = GetMediaPlayer(player_id); - if (player) - player->OnBufferUpdate(buffer_range); -} - -void RendererMediaPlayerManagerTizen::OnReadyStateChange( - int player_id, - media::MediaPlayerTizen::ReadyState state) { - media::WebMediaPlayerTizen* player = GetMediaPlayer(player_id); - if (player) - player->SetReadyState( - static_cast(state)); -} - -void RendererMediaPlayerManagerTizen::OnNetworkStateChange( - int player_id, - media::MediaPlayerTizen::NetworkState state) { - media::WebMediaPlayerTizen* player = GetMediaPlayer(player_id); - if (player) - player->SetNetworkState( - static_cast(state)); -} - -void RendererMediaPlayerManagerTizen::OnTimeChanged(int player_id) { - media::WebMediaPlayerTizen* player = GetMediaPlayer(player_id); - if (player) - player->OnTimeChanged(); -} - -void RendererMediaPlayerManagerTizen::OnPauseStateChange( - int player_id, - bool state) { - media::WebMediaPlayerTizen* player = GetMediaPlayer(player_id); - if (player) - player->OnPauseStateChange(state); -} - -void RendererMediaPlayerManagerTizen::OnSeekStateChange( - int player_id, - bool state) { - media::WebMediaPlayerTizen* player = GetMediaPlayer(player_id); - if (player) - player->OnSeekStateChange(state); -} - -void RendererMediaPlayerManagerTizen::OnRequestSeek( - int player_id, - double seek_time) { - media::WebMediaPlayerTizen* player = GetMediaPlayer(player_id); - if (player) - player->OnRequestSeek(seek_time); -} - -void RendererMediaPlayerManagerTizen::OnNewFrameAvailable( - int player_id, - base::SharedMemoryHandle foreign_memory_handle, - uint32 length, base::TimeDelta timestamp) { - media::WebMediaPlayerTizen* player = GetMediaPlayer(player_id); - // FIXME: Handle exception for all APIs. - if (player) - player->OnNewFrameAvailable(foreign_memory_handle, length, timestamp); -} - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -void RendererMediaPlayerManagerTizen::OnPlatformSurfaceUpdated( - int player_id, - int pixmap_id, - base::TimeDelta timestamp) { - media::WebMediaPlayerTizen* player = GetMediaPlayer(player_id); - if (player) - player->OnPlatformSurfaceUpdated(pixmap_id, timestamp); -} -#endif - -media::WebMediaPlayerTizen* RendererMediaPlayerManagerTizen::GetMediaPlayer( - int player_id) { - std::map::iterator iter = - media_players_.find(player_id); - if (iter != media_players_.end()) - return iter->second; - - return NULL; -} - -void RendererMediaPlayerManagerTizen::Play(int player_id) { - Send(new MediaPlayerGstHostMsg_Play(routing_id(), player_id)); -} - -void RendererMediaPlayerManagerTizen::Pause( - int player_id, - bool is_media_related_action) { - Send(new MediaPlayerGstHostMsg_Pause(routing_id(), player_id)); -} - -void RendererMediaPlayerManagerTizen::Seek(int player_id, double time) { - Send(new MediaPlayerGstHostMsg_Seek(routing_id(), player_id, time)); -} - -void RendererMediaPlayerManagerTizen::SetVolume(int player_id, double volume) { - Send(new MediaPlayerGstHostMsg_SetVolume(routing_id(), player_id, volume)); -} - -void RendererMediaPlayerManagerTizen::SetRate(int player_id, double rate) { - Send(new MediaPlayerGstHostMsg_SetRate(routing_id(), player_id, rate)); -} - -void RendererMediaPlayerManagerTizen::DestroyPlayer(int player_id) { - VLOG(1) << "RendererMediaPlayerManagerTizen::" << __FUNCTION__ - << " Plyer-Id = " << player_id; - Send(new MediaPlayerGstHostMsg_DeInit(routing_id(), player_id)); -} - -int RendererMediaPlayerManagerTizen::RegisterMediaPlayer( - media::WebMediaPlayerTizen* player) { - media_players_[next_media_player_id_] = player; - return next_media_player_id_++; -} - -void RendererMediaPlayerManagerTizen::UnregisterMediaPlayer(int player_id) { - VLOG(1) << "RendererMediaPlayerManagerTizen::" << __FUNCTION__ - << " Player-Id = " << player_id; - media_players_.erase(player_id); -} - -} // namespace content diff --git a/tizen_src/impl/content/renderer/media/tizen/renderer_media_player_manager_tizen.h b/tizen_src/impl/content/renderer/media/tizen/renderer_media_player_manager_tizen.h deleted file mode 100644 index 8f1140e2ee18..000000000000 --- a/tizen_src/impl/content/renderer/media/tizen/renderer_media_player_manager_tizen.h +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_RENDERER_MEDIA_TIZEN_RENDERER_MEDIA_PLAYER_TIZEN_MANAGER_H_ -#define CONTENT_RENDERER_MEDIA_TIZEN_RENDERER_MEDIA_PLAYER_TIZEN_MANAGER_H_ - -#include "content/public/renderer/render_frame_observer.h" -#include "media/base/tizen/media_player_tizen.h" -#include "media/base/tizen/webmediaplayer_tizen.h" -#include "url/gurl.h" - -namespace media { -class WebMediaPlayerTizen; -} - -namespace content { - -class RendererMediaPlayerManagerTizen : public RenderFrameObserver { - public: - // Constructs a RendererMediaPlayerManagerTizen object for the |render_frame|. - explicit RendererMediaPlayerManagerTizen(RenderFrame* render_frame); - virtual ~RendererMediaPlayerManagerTizen(); - - // Initializes a MediaPlayerTizen object in browser process. - void Initialize( - int player_id, - MediaPlayerHostMsg_Initialize_Type type, - const GURL& url, - double volume, - int demuxer_client_id); - - // Starts the player. - void Play(int player_id); - - // Pauses the player. - // is_media_related_action should be true if this pause is coming from an - // an action that explicitly pauses the video (user pressing pause, JS, etc.) - // Otherwise it should be false if Pause is being called due to other reasons - // (cleanup, freeing resources, etc.) - void Pause(int player_id, bool is_media_related_action); - - // Performs seek on the player. - void Seek(int player_id, double time); - - // Sets the player volume. - void SetVolume(int player_id, double volume); - - // Sets the playback rate. - void SetRate(int player_id, double rate); - - // Destroys the player in the browser process - void DestroyPlayer(int player_id); - - // Registers and unregisters a WebMediaPlayerTizen object. - int RegisterMediaPlayer(media::WebMediaPlayerTizen* player); - void UnregisterMediaPlayer(int player_id); - - bool OnMessageReceived(const IPC::Message& message) override; - - media::WebMediaPlayerTizen* GetMediaPlayer(int player_id); - - //Pause the playing media players when tab/webpage goes to background - void PausePlayingPlayers(); - - private: - void OnNewFrameAvailable( - int player_id, - base::SharedMemoryHandle foreign_memory_handle, - uint32 length, base::TimeDelta timestamp); - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - void OnPlatformSurfaceUpdated( - int player_id, - int pixmap_id, - base::TimeDelta timestamp); -#endif - - void OnMediaDataChange( - int player_id, - int format, - int height, - int width, - int media); - void OnDurationChange(int player_id, double duration); - void OnTimeUpdate(int player_id, double current_time); - void OnBufferUpdate( - int player_id, - std::vector buffer_range); - void OnTimeChanged(int player_id); - void OnPauseStateChange(int player_id, bool state); - void OnSeekStateChange(int player_id, bool state); - void OnRequestSeek(int player_id, double seek_time); - void OnReadyStateChange( - int player_id, - media::MediaPlayerTizen::ReadyState state ); - void OnNetworkStateChange( - int player_id, - media::MediaPlayerTizen::NetworkState state ); - - private: - std::map media_players_; - - int next_media_player_id_; - - DISALLOW_COPY_AND_ASSIGN(RendererMediaPlayerManagerTizen); -}; - -} // namespace content - -#endif // CONTENT_RENDERER_MEDIA_TIZEN_RENDERER_MEDIA_PLAYER_TIZEN_MANAGER_H_ diff --git a/tizen_src/impl/media/audio/tizen/audio_session_manager.cc b/tizen_src/impl/media/audio/tizen/audio_session_manager.cc deleted file mode 100644 index b308e66178a0..000000000000 --- a/tizen_src/impl/media/audio/tizen/audio_session_manager.cc +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (C) 2014 Samsung Electronics. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "media/audio/tizen/audio_session_manager.h" - -#include -#include -#include -#include - -#include "base/logging.h" -#include "config.h" - -namespace media { - -AudioSessionManager::AudioSessionManager() - : m_eventType_(ASM_EVENT_NONE) - , m_handle_(-1) - , m_notifyCallback_(0) - , m_processIdentifier_(getpid()) - , m_sessionType_(MM_SESSION_TYPE_NUM) - , m_stateType_(ASM_STATE_NONE) - , m_allocated_(false) - , m_resources_() { -} - -AudioSessionManager::~AudioSessionManager() { - if (m_allocated_) - DeallocateResources(); - - UnregisterAudioSessionManager(); -} - -bool AudioSessionManager::RegisterAudioSessionManager( - MMSessionType sessiontype, - ASM_sound_cb_t notifyCallback, - void* callbackData) { - int error = _mm_session_util_read_type - (m_processIdentifier_, reinterpret_cast(&m_sessionType_)); - if (error) { - m_sessionType_ = sessiontype; - error = mm_session_init((int)m_sessionType_); - if (error) { - LOG(ERROR) << "mm_session_init() failed."; - return false; - } - } - m_eventType_ = InterpretSessionToEvent(m_sessionType_); - m_notifyCallback_ = notifyCallback; - if (!ASM_register_sound - (m_processIdentifier_, &m_handle_, m_eventType_, m_stateType_, - m_notifyCallback_, callbackData, ASM_RESOURCE_NONE, &error)) { - LOG(ERROR) << "register is failed. errcode = " << error; - return false; - } - return true; -} - -bool AudioSessionManager::UnregisterAudioSessionManager() { - int error = 0; - if (!ASM_unregister_sound(m_handle_, m_eventType_, &error)) { - LOG(ERROR) << "unregister is failed. errcode = " << error; - return false; - } - return true; -} - -int AudioSessionManager::GetSoundState(ASM_sound_states_t* state) { - int error = 0; - if (!ASM_get_sound_state( m_handle_, m_eventType_, state, &error)) - LOG(ERROR) << "getSoundState is failed. errcode = " << error; - return error; -} - -bool AudioSessionManager::SetSoundState(ASM_sound_states_t state) { - int error = 0; - if (!ASM_set_sound_state( - m_handle_, m_eventType_, state, ASM_RESOURCE_NONE, &error)) { - LOG(ERROR) << "setSoundState is failed. errcode = " << error; - return false; - } - return true; -} - -ASM_sound_events_t AudioSessionManager::InterpretSessionToEvent( - MMSessionType sessionType) { - switch (sessionType) { - case MM_SESSION_TYPE_SHARE: - return ASM_EVENT_SHARE_MMPLAYER; - case MM_SESSION_TYPE_EXCLUSIVE: - return ASM_EVENT_EXCLUSIVE_MMPLAYER; - default: - return ASM_EVENT_NONE; - } -} - -bool AudioSessionManager::AllocateResources(GstElement* element) { - GList* list = NULL; - gst_element_query_resource(element, &list); - - ASM_request_resources_t toAllocate; - toAllocate.requested_resources_num = 0; - int i = 0; - for (GList* resource(list); resource; resource = resource->next) { - toAllocate.device_category[toAllocate.requested_resources_num] - = static_cast(GPOINTER_TO_INT(resource->data)); - toAllocate.access_right[toAllocate.requested_resources_num] - = ASM_RESOURCE_ACCESS_RIGHT_EXCLUSIVE; - - ++toAllocate.requested_resources_num; - } - g_list_free(list); - - if (!toAllocate.requested_resources_num) { - LOG(ERROR) << "No resources requested by : " << GST_ELEMENT_NAME(element); - return true; - } - - if (MAX_RESOURCE_NUM < toAllocate.requested_resources_num - + m_resources_.requested_resources_num) { - toAllocate.requested_resources_num = 0; - return false; - } - - int error(0); - ASM_allocate_resources(m_handle_, &toAllocate, false, &error); - if (error) { - LOG(ERROR) << "Error allocating ASM resource. errcode : " << error; - return false; - } - - // Register this resources as allocated for future deallocation - for (int i = 0; i < toAllocate.requested_resources_num; ++i) { - m_resources_.device_id[m_resources_.requested_resources_num] - = toAllocate.device_id[i]; - m_resources_.device_category[m_resources_.requested_resources_num] - = toAllocate.device_category[i]; - m_resources_.access_right[m_resources_.requested_resources_num] - = toAllocate.access_right[i]; - ++m_resources_.requested_resources_num; - } - m_allocated_ = true; - return true; -} - -bool AudioSessionManager::DeallocateResources() { - // No good rollback from failure during resource deallocation. - // The only smart move in this case would be to kill process, - // but do we really want to do it? - // Hence we ignore possible errors during resource deallocation. - int error(0); - m_allocated_ = !ASM_deallocate_resources(m_handle_, &m_resources_, &error); - if (error) - LOG(ERROR) << "Error deallocating ASM resources. errcode : " << error; - m_resources_.requested_resources_num = 0; - return !m_allocated_; -} - -} diff --git a/tizen_src/impl/media/audio/tizen/audio_session_manager.h b/tizen_src/impl/media/audio/tizen/audio_session_manager.h deleted file mode 100644 index 9b88505ac191..000000000000 --- a/tizen_src/impl/media/audio/tizen/audio_session_manager.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2014 Samsung Electronics. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef AUDIO_SESSION_MANAGER_H_ -#define AUDIO_SESSION_MANAGER_H_ - -#include -#include -#include -#include - -#include "base/memory/ref_counted.h" - -namespace media { - -class AudioSessionManager : public base::RefCounted { -public: - static scoped_refptr CreateAudioSessionManager() { - return make_scoped_refptr(new AudioSessionManager()); - } - - static void SetVolumeSessionToMediaType(); - static void ClearVolumeSessionFromMediaType(); - - virtual ~AudioSessionManager(); - - bool RegisterAudioSessionManager(MMSessionType, ASM_sound_cb_t, void*); - bool UnregisterAudioSessionManager(); - - int GetSoundState(ASM_sound_states_t*); - bool SetSoundState(ASM_sound_states_t); - ASM_sound_events_t InterpretSessionToEvent(MMSessionType); - bool AllocateResources(GstElement*); - bool DeallocateResources(); - - bool IsEmpty() const; - -private: - AudioSessionManager(); - - ASM_sound_cb_t m_notifyCallback_; - ASM_sound_events_t m_eventType_; - ASM_sound_states_t m_stateType_; - ASM_request_resources_t m_resources_; - - MMSessionType m_sessionType_; - - bool m_allocated_; - int m_handle_; - int m_processIdentifier_; -}; -} -#endif diff --git a/tizen_src/impl/media/base/tizen/demuxer_stream_player_params_tizen.cc b/tizen_src/impl/media/base/tizen/demuxer_stream_player_params_tizen.cc deleted file mode 100644 index e759eb290abe..000000000000 --- a/tizen_src/impl/media/base/tizen/demuxer_stream_player_params_tizen.cc +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "media/base/tizen/demuxer_stream_player_params_tizen.h" - -namespace media { - -DemuxerConfigs::DemuxerConfigs() - : audio_codec(kUnknownAudioCodec), - audio_channels(0), - audio_sampling_rate(0), - is_audio_encrypted(false), - video_codec(kUnknownVideoCodec), - is_video_encrypted(false), - duration_ms(0) {} - -DemuxerConfigs::~DemuxerConfigs() {} - -DemuxedBufferMetaData::DemuxedBufferMetaData() - : size(0), - end_of_stream(false), - type(DemuxerStream::UNKNOWN), - status(DemuxerStream::kAborted) {} - -DemuxedBufferMetaData::~DemuxedBufferMetaData() {} - -} // namespace media diff --git a/tizen_src/impl/media/base/tizen/demuxer_stream_player_params_tizen.h b/tizen_src/impl/media/base/tizen/demuxer_stream_player_params_tizen.h deleted file mode 100644 index 8e07db7fe7df..000000000000 --- a/tizen_src/impl/media/base/tizen/demuxer_stream_player_params_tizen.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MEDIA_BASE_TIZEN_DEMUXER_STREAM_PLAYER_PARAMS_TIZEN_H_ -#define MEDIA_BASE_TIZEN_DEMUXER_STREAM_PLAYER_PARAMS_TIZEN_H_ - -#include - -#include "media/base/audio_decoder_config.h" -#include "media/base/decrypt_config.h" -#include "media/base/demuxer_stream.h" -#include "media/base/media_export.h" -#include "media/base/video_decoder_config.h" -#include "ui/gfx/size.h" - -namespace media { - -struct MEDIA_EXPORT DemuxerConfigs { - DemuxerConfigs(); - ~DemuxerConfigs(); - - AudioCodec audio_codec; - int audio_channels; - int audio_sampling_rate; - bool is_audio_encrypted; - std::vector audio_extra_data; - - VideoCodec video_codec; - gfx::Size video_size; - bool is_video_encrypted; - std::vector video_extra_data; - - int duration_ms; -}; - -struct MEDIA_EXPORT DemuxedBufferMetaData { - DemuxedBufferMetaData(); - ~DemuxedBufferMetaData(); - - int size; - bool end_of_stream; - base::TimeDelta timestamp; - base::TimeDelta time_duration; - DemuxerStream::Type type; - DemuxerStream::Status status; -}; - -}; // namespace media - -#endif // MEDIA_BASE_TIZEN_DEMUXER_STREAM_PLAYER_PARAMS_TIZEN_H_ diff --git a/tizen_src/impl/media/base/tizen/demuxer_tizen.h b/tizen_src/impl/media/base/tizen/demuxer_tizen.h deleted file mode 100644 index 25874addfc4d..000000000000 --- a/tizen_src/impl/media/base/tizen/demuxer_tizen.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MEDIA_BASE_TIZEN_DEMUXER_TIZEN_H_ -#define MEDIA_BASE_TIZEN_DEMUXER_TIZEN_H_ - -#include "media/base/tizen/demuxer_stream_player_params_tizen.h" - -namespace media { - -// Defines the client callback interface. -class MEDIA_EXPORT DemuxerTizenClient { - public: - - // Called in response to RequestDemuxerConfigs() and also when the demuxer - // has initialized. - virtual void OnDemuxerConfigsAvailable(const DemuxerConfigs& params) = 0; - - // Called in response to RequestDemuxerData(). - virtual void OnDemuxerDataAvailable( - base::SharedMemoryHandle foreign_memory_handle, - const media::DemuxedBufferMetaData& meta_data) = 0; - - // Called in response to RequestDemuxerData() when no data is available. - virtual void OnBufferMetaDataAvailable( - const media::DemuxedBufferMetaData& meta_data) = 0; - - // Called to inform demuxer seek completion. - virtual void OnDemuxerSeekDone( - const base::TimeDelta& actual_browser_seek_time) = 0; - - // Called whenever the demuxer has detected a duration change. - virtual void OnDemuxerDurationChanged(base::TimeDelta duration) = 0; - - protected: - virtual ~DemuxerTizenClient() {} -}; - -// Defines a demuxer with asynchronous operations. -class MEDIA_EXPORT DemuxerTizen { - public: - virtual ~DemuxerTizen() {} - - // Initializes this demuxer with |client| as the callback handler. - // Must be called prior to calling any other methods. - virtual void Initialize(DemuxerTizenClient* client) = 0; - - // Called to request the current audio/video decoder configurations. - virtual void RequestDemuxerConfigs() = 0; - - // Called to request demuxer seek. - virtual void RequestDemuxerSeek(const base::TimeDelta& time_to_seek) = 0; - - // Called to request additional data from the demuxer. - virtual void RequestDemuxerData(media::DemuxerStream::Type type) = 0; -}; - -} // namespace media - -#endif // MEDIA_BASE_TIZEN_DEMUXER_TIZEN_H_ \ No newline at end of file diff --git a/tizen_src/impl/media/base/tizen/media_player_bridge_capi.cc b/tizen_src/impl/media/base/tizen/media_player_bridge_capi.cc deleted file mode 100755 index 5d6826b1ba89..000000000000 --- a/tizen_src/impl/media/base/tizen/media_player_bridge_capi.cc +++ /dev/null @@ -1,748 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "media/base/tizen/media_player_bridge_capi.h" - -#include "base/basictypes.h" -#include "base/command_line.h" -#include "base/logging.h" -#include "base/memory/shared_memory.h" -#include "base/message_loop/message_loop_proxy.h" -#include "base/strings/string_util.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/common/content_switches.h" -#include "media/base/tizen/media_player_manager_tizen.h" -#include "ui/gfx/size.h" - -#if defined(OS_TIZEN_MOBILE) -#include -#endif - -namespace { -// Update duration every 100ms. -const int kDurationUpdateInterval = 100; -} - -namespace media { -struct ErrorList { - player_error_e error_code; - std::string error_message; -}; - -// Modify this when new error information is added to |errorlist|. -const int ERROR_MAX = 18; - -const struct ErrorList errorlist[ERROR_MAX] = { - {PLAYER_ERROR_OUT_OF_MEMORY, "PLAYER_ERROR_OUT_OF_MEMORY"}, - {PLAYER_ERROR_INVALID_PARAMETER, "PLAYER_ERROR_INVALID_PARAMETER"}, - {PLAYER_ERROR_NO_SUCH_FILE, "PLAYER_ERROR_NO_SUCH_FILE"}, - {PLAYER_ERROR_INVALID_OPERATION, "PLAYER_ERROR_INVALID_OPERATION"}, - {PLAYER_ERROR_FILE_NO_SPACE_ON_DEVICE, - "PLAYER_ERROR_FILE_NO_SPACE_ON_DEVICE"}, -#if defined(OS_TIZEN_MOBILE) - {PLAYER_ERROR_FEATURE_NOT_SUPPORTED_ON_DEVICE, - "PLAYER_ERROR_FEATURE_NOT_SUPPORTED_ON_DEVICE"}, -#endif - {PLAYER_ERROR_SEEK_FAILED, "PLAYER_ERROR_SEEK_FAILED"}, - {PLAYER_ERROR_INVALID_STATE, "PLAYER_ERROR_INVALID_STATE"}, - {PLAYER_ERROR_NOT_SUPPORTED_FILE, "PLAYER_ERROR_NOT_SUPPORTED_FILE"}, - {PLAYER_ERROR_INVALID_URI, "PLAYER_ERROR_INVALID_URI"}, - {PLAYER_ERROR_SOUND_POLICY, "PLAYER_ERROR_SOUND_POLICY"}, - {PLAYER_ERROR_CONNECTION_FAILED, "PLAYER_ERROR_CONNECTION_FAILED"}, - {PLAYER_ERROR_VIDEO_CAPTURE_FAILED, "PLAYER_ERROR_VIDEO_CAPTURE_FAILED"}, - {PLAYER_ERROR_DRM_EXPIRED, "PLAYER_ERROR_DRM_EXPIRED"}, - {PLAYER_ERROR_DRM_NO_LICENSE, "PLAYER_ERROR_DRM_NO_LICENSE"}, - {PLAYER_ERROR_DRM_FUTURE_USE, "PLAYER_ERROR_DRM_FUTURE_USE"}, - {PLAYER_ERROR_DRM_NOT_PERMITTED, "PLAYER_ERROR_DRM_NOT_PERMITTED"}, - {PLAYER_ERROR_RESOURCE_LIMIT, "PLAYER_ERROR_RESOURCE_LIMIT"}}; - -static Eina_Bool notify_damage_updated_cb(void* data, int type, void* event) { - MediaPlayerBridgeCapi* player = static_cast (data); - if (!player) - return ECORE_CALLBACK_PASS_ON; - - player->PlatformSurfaceUpdated(); - return ECORE_CALLBACK_PASS_ON; -} - -static double ConvertMilliSecondsToSeconds(int time) { - double seconds = static_cast(time) / - (base::Time::kMillisecondsPerSecond); - return seconds; -} - -static double ConvertSecondsToMilliSeconds(double time) { - if (time < 0) { - LOG(ERROR) << "Invalid time:" << time << " Reset to 0"; - time = 0; - } - double seconds = static_cast(time) * - (base::Time::kMillisecondsPerSecond); - return seconds; -} - -// Called by player_prepare_async() -void player_prepared_cb(void* user_data) { - MediaPlayerBridgeCapi* player = - static_cast(user_data); - - if (!player) - return; - - player->SetPixmap(); - player->ExecuteDelayedPlayerState(); -} - -// Called by player_set_x11_display_pixmap() -unsigned int pixmap_buffer_ready_cb(void *user_data) { - MediaPlayerBridgeCapi* player = - static_cast(user_data); - - if (!player) - return -1; - - return player->GetSurfaceID(); -} - -// Called by player_set_completed_cb() -void playback_complete_cb(void* user_data) { - MediaPlayerBridgeCapi* player = - static_cast(user_data); - - if (!player) - return; - - player->PlaybackCompleteUpdate(); -} - -// Called by player_set_play_position() -void seek_complete_cb(void* user_data) { - MediaPlayerBridgeCapi* player = - static_cast(user_data); - - if (!player) - return; - - player->SeekCompleteUpdate(); -} - -// Called by player_set_buffering_cb() -void changed_buffering_status_cb(int percent, void *user_data) { - MediaPlayerBridgeCapi* player = - static_cast(user_data); - - if (!player) - return; - - player->HandleBufferingStatus(percent); -} - -// Called by player_set_error_cb() -void error_cb(int error_code, void *user_data) { - MediaPlayerBridgeCapi* player = - static_cast(user_data); - - if (!player) - return; - - player->HandleError(error_code, "error_cb"); -} - -// Called by player_set_interrupted_cb() -void interrupt_cb(player_interrupted_code_e code, void *user_data) { - MediaPlayerBridgeCapi* player = - static_cast(user_data); - - if (!player) - return; - - // FIMXE: Add interrupt handling -} - -MediaPlayerBridgeCapi::MediaPlayerBridgeCapi( - int player_id, - const GURL& url, - double volume, - MediaPlayerManager* manager_in) - : MediaPlayerTizen(player_id, manager_in), - pixmap_id_(0), - efl_pixmap_(0), - m_damage(0), - m_damageHandler(NULL), - main_loop_(base::MessageLoopProxy::current()), - player_(NULL), - url_(url), - media_type_(0), - player_width_(0), - player_height_(0), - video_format_(0), - is_end_reached_(false), - is_file_url_(false), - is_paused_(true), - is_pixmap_used_(true), - is_seeking_(false), - duration_(0), - seek_duration_(0), - playback_rate_(1.0), - delayed_player_state_(0), - shared_memory_size(0) { - VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); - int ret = player_create(&player_); - if (ret == PLAYER_ERROR_NONE) { - VLOG(1) << __FUNCTION__ << " : Create Player Success."; - VLOG(1) << __FUNCTION__ << " : URL = " << url_.spec().c_str(); - player_set_uri(player_, url_.spec().c_str()); - player_set_sound_type(player_, SOUND_TYPE_MEDIA); - player_set_volume(player_, (float)volume, (float)volume); - - // Use Pixmap - ret = player_set_x11_display_pixmap(player_, - pixmap_buffer_ready_cb, this); - if (ret != PLAYER_ERROR_NONE) { - HandleError(ret, "player_set_x11_display_pixmap"); - return; - } - player_set_completed_cb(player_, playback_complete_cb, this); - player_set_buffering_cb(player_, changed_buffering_status_cb, this); - player_set_interrupted_cb(player_, interrupt_cb, this); - player_set_error_cb(player_, error_cb, this); -#if defined(OS_TIZEN_MOBILE) - player_set_display_visible (player_, true); -#else // OS_TIZEN_TV - player_set_x11_display_visible (player_, true); -#endif - if(url_.SchemeIsFile()) - is_file_url_ = true; - - manager()->OnReadyStateChange(GetPlayerId(), - MediaPlayerTizen::ReadyStateHaveEnoughData); - manager()->OnNetworkStateChange(GetPlayerId(), - MediaPlayerTizen::NetworkStateLoaded); - - } else { - HandleError(ret, "player_create"); - } -} - -MediaPlayerBridgeCapi::~MediaPlayerBridgeCapi() { - VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); -} - -void MediaPlayerBridgeCapi::Destroy() { - VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); - if (IsPlayerDestructing()) - return; - destructing_ = true; - StopCurrentTimeUpdateTimer(); - StopBufferingUpdateTimer(); - player_unset_completed_cb(player_); - player_unset_interrupted_cb(player_); - player_unset_error_cb(player_); - player_unset_buffering_cb(player_); - player_unset_subtitle_updated_cb(player_); - player_destroy(player_); - - if (m_damage) { - ecore_x_damage_free(m_damage); - m_damage = 0; - } - if (m_damageHandler) { - ecore_event_handler_del(m_damageHandler); - m_damageHandler = NULL; - } - if (efl_pixmap_.get()) { - efl_pixmap_ = NULL; - } - main_loop_->DeleteSoon(FROM_HERE, this); -} - -void MediaPlayerBridgeCapi::Play() { - VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); - if (GetPlayerState() == PLAYER_STATE_IDLE) { - if(delayed_player_state_ != 0) { - delayed_player_state_ = DELAYED_PLAYER_STATE_PLAY; - return; - } - delayed_player_state_ = DELAYED_PLAYER_STATE_PLAY; - int ret = player_prepare_async(player_, player_prepared_cb, this); - if (ret != PLAYER_ERROR_NONE) - HandleError(ret, "player_prepare_async"); - return; - } - - if (playback_rate_ == 0.0) { - is_paused_ = false; - return; - } - if (player_start(player_) != PLAYER_ERROR_NONE) { - LOG(ERROR) <<"Play() -> |player_start| failed"; - return; - } - -#if defined(OS_TIZEN_MOBILE) - if (device_power_request_lock(POWER_LOCK_DISPLAY, 0) != DEVICE_ERROR_NONE) - LOG(ERROR) <<"Play() -> |device_power_request_lock| failed"; -#endif - main_loop_->PostTask( - FROM_HERE, - base::Bind( - &MediaPlayerBridgeCapi::StartCurrentTimeUpdateTimer, - base::Unretained(this))); - if (!is_file_url_) - main_loop_->PostTask( - FROM_HERE, - base::Bind( - &MediaPlayerBridgeCapi::StartBufferingUpdateTimer, - base::Unretained(this))); - is_paused_ = false; - is_end_reached_ = false; -} - -void MediaPlayerBridgeCapi::Pause(bool is_media_related_action) { - VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); - if (GetPlayerState() == PLAYER_STATE_IDLE) { - if(delayed_player_state_ != 0) { - delayed_player_state_ = DELAYED_PLAYER_STATE_PAUSE; - return; - } - delayed_player_state_ = DELAYED_PLAYER_STATE_PAUSE; - int ret = player_prepare_async(player_, player_prepared_cb, this); - if (ret != PLAYER_ERROR_NONE) - HandleError(ret, "player_prepare_async"); - return; - } - - if (player_pause(player_) != PLAYER_ERROR_NONE) { - LOG(ERROR) << "Pause() -> |player_pause| failed"; - return; - } - - if (!is_file_url_) - main_loop_->PostTask( - FROM_HERE, - base::Bind( - &MediaPlayerBridgeCapi::StartBufferingUpdateTimer, - base::Unretained(this))); - -#if defined(OS_TIZEN_MOBILE) - if (device_power_release_lock(POWER_LOCK_DISPLAY) != DEVICE_ERROR_NONE) - LOG(ERROR) << "|device_power_release_lock| request failed"; -#endif - - StopCurrentTimeUpdateTimer(); - is_paused_ = true; -} - -void MediaPlayerBridgeCapi::SetRate(double rate) { - VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); - if (playback_rate_ == rate) - return; - - if (rate == 0.0) { - playback_rate_ = rate; - Pause(true); - return; - } - - // Fixme: SetRate is always failing - if (player_set_playback_rate(player_, (float)rate) != PLAYER_ERROR_NONE) - LOG(ERROR) <<"|player_set_playback_rate|failed"; - else { - // If previous rate was zero and requested rate is non-zero, change the - // playback rate and call play - if(playback_rate_ == 0.0 && rate != 0.0) { - playback_rate_ = rate; - Play(); - } else { - playback_rate_ = rate; - } - } -} - -void MediaPlayerBridgeCapi::Seek(const double time) { - VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); -#if defined(OS_TIZEN_MOBILE) - int err = player_set_play_position(player_, - ConvertSecondsToMilliSeconds(time), true, seek_complete_cb, this); -#else // OS_TIZEN_TV - int err = player_set_position(player_, - ConvertSecondsToMilliSeconds(time), seek_complete_cb, this); -#endif - if(err != PLAYER_ERROR_NONE) { - LOG(ERROR) <<"|player_set_playback_rate|failed"; - manager()->OnTimeUpdate(GetPlayerId(), GetCurrentTime()); - manager()->OnTimeChanged(GetPlayerId()); - return; - } - - if (!is_paused_) - StopCurrentTimeUpdateTimer(); - - StopBufferingUpdateTimer(); - UpdateSeekState(true); - seek_duration_ = time; - is_end_reached_ = time != duration_ ? false : true; - manager()->OnTimeUpdate(GetPlayerId(), time); - - if (!is_paused_) - main_loop_->PostTask( - FROM_HERE, - base::Bind( - &MediaPlayerBridgeCapi::StartCurrentTimeUpdateTimer, - base::Unretained(this))); -} - -void MediaPlayerBridgeCapi::Release() { -} - -void MediaPlayerBridgeCapi::SetVolume(double volume) { - VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId() - << " : Volume : " << volume; - if (GetPlayerState() > PLAYER_STATE_IDLE){ - if(volume == 0.0){ - if(player_set_mute(player_,true) - != PLAYER_ERROR_NONE) - LOG(ERROR) << "|player_set_mute(true)| failed in MediaPlayerBridgeCapi::" - << __FUNCTION__; - - return; - } - - if(player_set_mute(player_,false) - != PLAYER_ERROR_NONE) - LOG(ERROR) << "|player_set_mute(false)| failed in MediaPlayerBridgeCapi::" - << __FUNCTION__; - - if (player_set_volume(player_, (float)volume, (float)volume) - != PLAYER_ERROR_NONE) - LOG(ERROR) << "|player_set_volume| failed in MediaPlayerBridgeCapi::" - << __FUNCTION__; - } -} - -void MediaPlayerBridgeCapi::UpdateMediaType() { - int fps = 0 ; - int bit_rate = 0; - int sample_rate = 0; - int channel = 0; - int audio_bit_rate = 0; - media_type_ = 0; - - int err = player_get_video_stream_info(player_, &fps, &bit_rate); - int err_audio = player_get_audio_stream_info(player_, - &sample_rate, &channel, &audio_bit_rate); - - VLOG(1) << "Audio Information: sample_rate = " << sample_rate - << " , channel = " << channel - << " , audio_bit_rate = " << audio_bit_rate; - - if (err != PLAYER_ERROR_NONE) { - HandleError(err, "player_get_video_stream_info"); - return; - } - - if (err_audio != PLAYER_ERROR_NONE) { - HandleError(err_audio, "player_get_audio_stream_info"); - return; - } - - if (sample_rate > 0) - media_type_ |= MEDIA_AUDIO_MASK; - - err = player_get_video_size(player_,&player_width_,&player_height_); - if (err != PLAYER_ERROR_NONE) { - HandleError(err, " player_get_video_size"); - return; - } - - VLOG(1) << "Video Information: fps = " << fps - << " , bit_rate = " << bit_rate - << " , Video Height = " << player_height_ - << " , Video Width = " << player_width_; - - // Video stream is present if both video width and video - // height are non-zero. - if (player_width_ != 0 && player_height_ != 0) - media_type_ |= MEDIA_VIDEO_MASK; - - // Passing NULL value for video_format. Its not required but - // |webmediaplayertizen| expects a value. - manager()->OnMediaDataChange(GetPlayerId(), video_format_, player_height_, - player_width_, media_type_); -} - -void MediaPlayerBridgeCapi::UpdateDuration() { - int duration = 0; - player_get_duration(player_, &duration); - - if (duration_ != ConvertMilliSecondsToSeconds(duration)) { - duration_ = ConvertMilliSecondsToSeconds(duration); - manager()->OnDurationChange(GetPlayerId(), duration_); - } - - // No need to buffer 'local file'. Update buffered percentage. - if(is_file_url_) { - std::vector buffer_range; - media::MediaPlayerTizen::TimeRanges range; - range.start = 0; - range.end = duration_ * base::Time::kMicrosecondsPerSecond; - buffer_range.push_back(range); - manager()->OnBufferUpdate(GetPlayerId(), buffer_range); - } -} - -double MediaPlayerBridgeCapi::GetCurrentTime() { - // For http://instagram.com/p/tMQOo0lWqm/ - // After playback completed current-time and duration are not equal. - if (is_end_reached_) { - if (is_seeking_) - return seek_duration_; - if (playback_rate_ < 0) - return 0.0f; - if (duration_) - return duration_; - } - - int postion = 0; -#if defined(OS_TIZEN_MOBILE) - player_get_play_position(player_, &postion); -#else // OS_TIZEN_TV - player_get_position(player_, &postion); -#endif - return ConvertMilliSecondsToSeconds(postion); -} - -void MediaPlayerBridgeCapi::OnCurrentTimeUpdateTimerFired() { - if (IsPlayerDestructing()) - return; - manager()->OnTimeUpdate(GetPlayerId(), GetCurrentTime()); - UpdateDuration(); -} - -void MediaPlayerBridgeCapi::StartCurrentTimeUpdateTimer() { - if (!current_time_update_timer_.IsRunning()) { - current_time_update_timer_.Start( - FROM_HERE, - base::TimeDelta::FromMilliseconds(kDurationUpdateInterval), - this, &MediaPlayerBridgeCapi::OnCurrentTimeUpdateTimerFired); - } -} - -void MediaPlayerBridgeCapi::StopCurrentTimeUpdateTimer() { - if (current_time_update_timer_.IsRunning()) - current_time_update_timer_.Stop(); -} - -void MediaPlayerBridgeCapi::OnBufferingUpdateTimerFired() { - if (IsPlayerDestructing()) - return; - - int start, current; - if (player_get_streaming_download_progress(player_, - &start, ¤t) == PLAYER_ERROR_NONE) { - if (current == 100) { - StopBufferingUpdateTimer(); - manager()->OnNetworkStateChange(GetPlayerId(), - MediaPlayerTizen::NetworkStateLoaded); - } - std::vector buffer_range; - media::MediaPlayerTizen::TimeRanges range; - range.start = 0; - range.end = static_cast(current) * duration_ / 100 - * base::Time::kMicrosecondsPerSecond; - buffer_range.push_back(range); - manager()->OnBufferUpdate(GetPlayerId(), buffer_range); - } -} - -void MediaPlayerBridgeCapi::StartBufferingUpdateTimer() { - if (!buffering_update_timer_.IsRunning()) { - buffering_update_timer_.Start( - FROM_HERE, - base::TimeDelta::FromMilliseconds(kDurationUpdateInterval), - this, &MediaPlayerBridgeCapi::OnBufferingUpdateTimerFired); - } -} - -void MediaPlayerBridgeCapi::StopBufferingUpdateTimer() { - if (buffering_update_timer_.IsRunning()) - buffering_update_timer_.Stop(); -} - -void MediaPlayerBridgeCapi::OnTimeChanged() { - DCHECK(main_loop_->BelongsToCurrentThread()); - manager()->OnTimeChanged(GetPlayerId()); -} - -void MediaPlayerBridgeCapi::PlaybackCompleteUpdate() { - VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); - is_end_reached_ = true; -#if defined(OS_TIZEN_MOBILE) - if (device_power_release_lock(POWER_LOCK_DISPLAY) != DEVICE_ERROR_NONE) - LOG(ERROR) << "|device_power_release_lock| request failed"; -#endif - - StopCurrentTimeUpdateTimer(); - manager()->OnTimeUpdate(GetPlayerId(), GetCurrentTime()); - manager()->OnTimeChanged(GetPlayerId()); -} - -void MediaPlayerBridgeCapi::SeekCompleteUpdate() { - UpdateSeekState(false); - manager()->OnTimeChanged(GetPlayerId()); - - if (!is_file_url_) - main_loop_->PostTask( - FROM_HERE, - base::Bind( - &MediaPlayerBridgeCapi::StartBufferingUpdateTimer, - base::Unretained(this))); -} - -void MediaPlayerBridgeCapi::UpdateSeekState(bool state) { - is_seeking_ = state; -} - -void MediaPlayerBridgeCapi::PlatformSurfaceUpdated() { - int postion = 0; -#if defined(OS_TIZEN_MOBILE) - player_get_play_position(player_, &postion); -#else // OS_TIZEN_TV - player_get_position(player_, &postion); -#endif - base::TimeDelta timestamp = base::TimeDelta::FromMilliseconds(postion); - manager()->OnPlatformSurfaceUpdated(GetPlayerId(), pixmap_id_, timestamp); -} - -void MediaPlayerBridgeCapi::SetPixmap() { - VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); - UpdateMediaType(); - UpdateDuration(); - if (media_type_ == 0) - return; - - if ((media_type_ & MEDIA_VIDEO_MASK) && !efl_pixmap_.get()) { - efl_pixmap_ = gfx::EflPixmap::Create(gfx::EflPixmap::SURFACE, - gfx::Size(player_width_, player_height_)); - if (!efl_pixmap_.get()) { - HandleError(0, " PixmapSurfaceTizen::create"); - return ; - } - is_pixmap_used_ = true; - pixmap_id_ = efl_pixmap_->GetId(); - - //Register to get notification from ecore for damage updates. - m_damage = ecore_x_damage_new(pixmap_id_, - ECORE_X_DAMAGE_REPORT_RAW_RECTANGLES); - m_damageHandler = ecore_event_handler_add(ECORE_X_EVENT_DAMAGE_NOTIFY, - notify_damage_updated_cb, this); - } - - manager()->OnReadyStateChange(GetPlayerId(), - MediaPlayerTizen::ReadyStateHaveEnoughData); - manager()->OnNetworkStateChange(GetPlayerId(), - MediaPlayerTizen::NetworkStateLoaded); -} - -int MediaPlayerBridgeCapi::GetSurfaceID() const { - return pixmap_id_; -} - -void MediaPlayerBridgeCapi::HandleBufferingStatus(int percent) { - if (IsPlayerDestructing()) - return; - - if (percent == 100 && !is_paused_ && !is_seeking_) { - if (GetPlayerState() == PLAYER_STATE_PAUSED) { - VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId() - << " : Playing MediaPlayer as buffer reached 100%"; - if (player_start(player_) != PLAYER_ERROR_NONE) { - LOG(ERROR) << "HandleBufferingStatus:player_start failed"; - return; - } - main_loop_->PostTask( - FROM_HERE, - base::Bind( - &MediaPlayerBridgeCapi::StartCurrentTimeUpdateTimer, - base::Unretained(this))); - if (!is_file_url_) - main_loop_->PostTask( - FROM_HERE, - base::Bind( - &MediaPlayerBridgeCapi::StartBufferingUpdateTimer, - base::Unretained(this))); - manager()->OnReadyStateChange(GetPlayerId(), - MediaPlayerTizen::ReadyStateHaveEnoughData); - manager()->OnNetworkStateChange(GetPlayerId(), - MediaPlayerTizen::NetworkStateLoading); - return; - } - } - - if (percent != 100 && !is_paused_ && !is_seeking_) { - if (GetPlayerState() == PLAYER_STATE_PLAYING) { - VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId() - << " : Pausing MediaPlayer as buffer is < 100%"; - if (player_pause(player_) != PLAYER_ERROR_NONE) { - LOG(ERROR) << "HandleBufferingStatus:player_pause failed"; - return; - } - StopCurrentTimeUpdateTimer(); - manager()->OnReadyStateChange(GetPlayerId(), - MediaPlayerTizen::ReadyStateHaveCurrentData); - manager()->OnNetworkStateChange(GetPlayerId(), - MediaPlayerTizen::NetworkStateLoading); - } - } -} - -// Helper method which prints errors occured while calling CAPI api's. -void MediaPlayerBridgeCapi::HandleError(int err, char const* from) { - int index; - for (index = 0; index < ERROR_MAX; index++) { - if (errorlist[index].error_code == err) { - LOG(ERROR) << "Stoping playback of media due to Error code : "<OnNetworkStateChange(GetPlayerId(), - MediaPlayerTizen::NetworkStateDecodeError); - -#ifdef OS_TIZEN_MOBILE - if (device_power_release_lock(POWER_LOCK_DISPLAY) != DEVICE_ERROR_NONE) - LOG(ERROR) << "|device_power_release_lock| request failed"; -#endif -} - -player_state_e MediaPlayerBridgeCapi::GetPlayerState() { - player_state_e state; - player_get_state(player_,&state); - return state; -} - -void MediaPlayerBridgeCapi::ExecuteDelayedPlayerState() { - switch (delayed_player_state_) { - case DELAYED_PLAYER_STATE_PLAY : - VLOG(1) << "Executing the delayed play command"; - Play(); - break; - case DELAYED_PLAYER_STATE_PAUSE : - VLOG(1) << "Executing the delayed pause command"; - Pause(false); - break; - default : - break; - } -} - -} // namespace media diff --git a/tizen_src/impl/media/base/tizen/media_player_bridge_capi.h b/tizen_src/impl/media/base/tizen/media_player_bridge_capi.h deleted file mode 100755 index a5836e164148..000000000000 --- a/tizen_src/impl/media/base/tizen/media_player_bridge_capi.h +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MEDIA_TIZEN_MEDIA_PLAYER_BRIDGE_CAPI_H_ -#define MEDIA_TIZEN_MEDIA_PLAYER_BRIDGE_CAPI_H_ - -#include -#if defined(TIZEN_V_2_4) -#include -#else -#include -#endif - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -#include -#include "ecore_x_wrapper.h" -#endif - -#include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" -#include "base/timer/timer.h" -#include "content/public/browser/browser_message_filter.h" -#include "media/base/ranges.h" -#include "media/base/tizen/media_player_tizen.h" -#include "media/base/video_frame.h" -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -#include "ui/gl/efl_pixmap.h" -#endif - -namespace media { - -class MEDIA_EXPORT MediaPlayerBridgeCapi - : public MediaPlayerTizen { - public: - MediaPlayerBridgeCapi(int player_id, - const GURL& url, - double volume, - MediaPlayerManager* manager); - virtual ~MediaPlayerBridgeCapi(); - - // MediaPlayerTizen implementation. - virtual void Destroy() override; - virtual void Play() override; - virtual void Pause(bool is_media_related_action) override; - virtual void SetRate(double rate) override; - virtual void Seek(const double time) override; - virtual void SetVolume(double volume) override; - virtual double GetCurrentTime() override; - - int GetSurfaceID() const; - void ExecuteDelayedPlayerState(); - void HandleBufferingStatus(int percent); - void HandleError(int ret, char const* from); - void PlatformSurfaceUpdated(); - void PlaybackCompleteUpdate(); - void SeekCompleteUpdate(); - void SetPixmap(); - - protected: - virtual void Release(); - - private: - // |duration_update_timer_| related - void OnCurrentTimeUpdateTimerFired(); - void StartCurrentTimeUpdateTimer(); - void StopCurrentTimeUpdateTimer(); - - // |buffering_update_timer_| related - void OnBufferingUpdateTimerFired(); - void StartBufferingUpdateTimer(); - void StopBufferingUpdateTimer(); - - void OnTimeChanged(); - void UpdateMediaType(); - void UpdateSeekState(bool state); - void UpdateDuration(); - - player_state_e GetPlayerState(); - - private: - int pixmap_id_; - scoped_refptr efl_pixmap_; - Ecore_X_Damage m_damage; - Ecore_Event_Handler* m_damageHandler; - - const scoped_refptr main_loop_; - - player_h player_; - GURL url_; - - int media_type_; - int player_width_; - int player_height_; - unsigned int video_format_; - - bool is_download_finished_; - bool is_end_reached_; - bool is_file_url_; - bool is_paused_; - bool is_pixmap_used_; - bool is_seeking_; - - double duration_; - double seek_duration_; - double playback_rate_; - - int delayed_player_state_; - const static int DELAYED_PLAYER_STATE_PLAY = 1; - const static int DELAYED_PLAYER_STATE_PAUSE = 2; - - base::SharedMemory shared_memory; - uint32 shared_memory_size; - base::SharedMemoryHandle foreign_memory_handle; - - base::RepeatingTimer current_time_update_timer_; - base::RepeatingTimer buffering_update_timer_; - - DISALLOW_COPY_AND_ASSIGN(MediaPlayerBridgeCapi); -}; - -} // namespace media - -#endif // MEDIA_TIZEN_MEDIA_PLAYER_BRIDGE_CAPI_H_ - diff --git a/tizen_src/impl/media/base/tizen/media_player_bridge_gstreamer.cc b/tizen_src/impl/media/base/tizen/media_player_bridge_gstreamer.cc deleted file mode 100644 index 055e3f05bd4a..000000000000 --- a/tizen_src/impl/media/base/tizen/media_player_bridge_gstreamer.cc +++ /dev/null @@ -1,1256 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "media/base/tizen/media_player_bridge_gstreamer.h" - -#include -#include -#include -#include - -#include "base/basictypes.h" -#include "base/message_loop/message_loop_proxy.h" -#include "media/base/tizen/media_player_manager_tizen.h" -#include "ui/gfx/size.h" - -#if defined(OS_TIZEN_MOBILE) && (defined(TIZEN_V_2_3) || defined(TIZEN_V_2_4)) -#include -#endif - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -#if GST_VERSION_MAJOR == 1 -#include -#else -#include -#endif -#endif - -namespace { - -// fourcc for gst-video-format -const uint32 GST_VIDEO_SN12 = GST_MAKE_FOURCC('S','N','1','2'); - -// tile size for SN12 -const uint SN12_TILE_WIDTH = 64; -const uint SN12_TILE_HEIGHT = 32; -const uint SN12_TILE_SIZE = SN12_TILE_WIDTH * SN12_TILE_HEIGHT; - -// GstPlayFlags in |gstplay-enum.h| -typedef enum { - GST_PLAY_FLAG_VIDEO = (1 << 0), - GST_PLAY_FLAG_AUDIO = (1 << 1), - GST_PLAY_FLAG_TEXT = (1 << 2), - GST_PLAY_FLAG_VIS = (1 << 3), - GST_PLAY_FLAG_SOFT_VOLUME = (1 << 4), - GST_PLAY_FLAG_NATIVE_AUDIO = (1 << 5), - GST_PLAY_FLAG_NATIVE_VIDEO = (1 << 6), - GST_PLAY_FLAG_DOWNLOAD = (1 << 7), - GST_PLAY_FLAG_BUFFERING = (1 << 8), - GST_PLAY_FLAG_DEINTERLACE = (1 << 9), - GST_PLAY_FLAG_SOFT_COLORBALANCE = (1 << 10) -} GstPlayFlags; - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -typedef enum { - DEGREE_0, // No rotate - DEGREE_90, // Rotate 90 degree count clockwise - DEGREE_180, // Rotate 180 degree count clockwise - DEGREE_270 // Rotate 270 degree count clockwise -} RotateAngle; -#endif - -// Playbin element name -const char* kPlaybinName = "gst_playbin"; -const char* kVideoSink = "gst_video_sink"; -const char* kPropertyBufferSize = "buffer-size"; -const char* kPropertyMaxBuffers = "max-buffers"; -const char* kPropertyVolume = "volume"; -const char* kPropertyUri = "uri"; -const char* kPropertyAudioStream = "n-audio"; -const char* kPropertyVideoStream = "n-video"; -const char* kPropertyTextStream = "n-text"; - -// Update duration every 100ms. -const int kDurationUpdateInterval = 100; -const int kMaxBuffer = 1; - -// sample size for audio/video buffering -const int kPreloadBufferSize = (3 * 1024 * 1024); // 3MB - -const GstClockTime ConvertToGstClockTime(double time) { - if (time < 0) { - LOG(ERROR) << "Invalid time:" << time << " Reset to 0"; - time = 0; - } - - // Extract the integer part of the time (seconds) and the fractional part - // (microseconds). Attempt to round the microseconds so no floating point - // precision is lost and we can perform an accurate seek. - double seconds = 0; - double microSeconds = std::modf(time, &seconds) * 1000000; - GTimeVal timeValue; - timeValue.tv_sec = static_cast(seconds); - timeValue.tv_usec = static_cast(lround(microSeconds / 10) * 10); - return GST_TIMEVAL_TO_TIME(timeValue); -} - -const double ConvertNanoSecondsToSeconds(int64 time) { - double seconds = static_cast(time) / - (base::Time::kNanosecondsPerSecond); - return seconds; -} - -} // namespace - -namespace media { - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -static Eina_Bool notify_damage_updated_cb(void* data, int type, void* event) { - MediaPlayerBridgeGstreamer* player = - static_cast (data); - if (!player) - return ECORE_CALLBACK_PASS_ON; - - player->PlatformSurfaceUpdated(); - return ECORE_CALLBACK_PASS_ON; -} - -static int get_pixmap_id_cb(void* data) { - MediaPlayerBridgeGstreamer* player = - static_cast (data); - return player->GetSurfaceID(); -} -#endif - -static GstBusSyncReply gst_pipeline_message_cb( - GstBus* bus, - GstMessage* message, - gpointer user_data) { - MediaPlayerBridgeGstreamer* player = - static_cast(user_data); - if (!player) - return GST_BUS_PASS; - - player->HandleMessage(message); - gst_message_unref(message); - return GST_BUS_DROP; -} - -static void on_gst_appsink_eos( - GstAppSink* appsink, - gpointer user_data) { - // EOS is Handled in state handling. Do nothing. -} - -// Audio part of GStreamer is not yet implemented. Workaround to handle -// |PREROLLED| for audio files is to update based on |GST_MESSAGE_BUFFERING|. -static GstFlowReturn on_gst_appsink_preroll( - GstAppSink* sink, - gpointer user_data) { - MediaPlayerBridgeGstreamer* player = - static_cast(user_data); - if (!player) - return GST_FLOW_ERROR; - player->PrerollComplete(); - return GST_FLOW_OK; -} - -static GstFlowReturn on_gst_appsink_sample( - GstAppSink* sink, - gpointer user_data) { - MediaPlayerBridgeGstreamer* player = - static_cast(user_data); - if (!player) - return GST_FLOW_ERROR; - - player->SampleReady(player->PullSample()); - return GST_FLOW_OK; -} - -static void on_gst_installer_result_function( - GstInstallPluginsReturn result, - gpointer userData) { - MediaPlayerBridgeGstreamer* player = - reinterpret_cast(userData); - player->HandlePluginInstallerResult(result); -} - -MediaPlayerBridgeGstreamer::MediaPlayerBridgeGstreamer( - int player_id, - const GURL& url, - double volume, - MediaPlayerManager* manager_in) - : MediaPlayerTizen(player_id, manager_in), - main_loop_(base::MessageLoopProxy::current()), - gst_playbin_(NULL), - gst_appsink_(NULL), - url_(url), - volume_(volume), - gst_width_(0), - gst_height_(0), - is_prerolled_(false), - is_paused_(true), - duration_(0), - playback_rate_(1.0f), - buffered_(0), - video_format_(0), - media_type_(0), - is_live_stream_(false), - is_file_url_(false), - is_end_reached_(false), - is_seeking_(false), - is_seek_pending_(false), - seek_duration_(0), - error_occured_(false), - missing_plugins_(false), - is_pixmap_used_(false), -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - pixmap_id_(0), - efl_pixmap_(NULL), - m_damage(0), - m_damageHandler(NULL), -#endif - bufsize_sn12_(0), - shared_memory_size(0) { - LOG(INFO) << "MediaPlayerBridgeGstreamer - URL = " << url_.spec().c_str(); - - // gstreamer port - if (!gst_is_initialized()) { - gst_init_check(NULL, NULL, 0); - } - - if (gst_is_initialized()) { -#if GST_VERSION_MAJOR == 1 - gst_playbin_ = gst_element_factory_make("playbin", kPlaybinName); -#else - gst_playbin_ = gst_element_factory_make("playbin2", kPlaybinName); -#endif - gst_appsink_ = GetVideoSink(); - if (gst_playbin_ && gst_appsink_) { - g_object_set(gst_playbin_, "video-sink", gst_appsink_, NULL); - - // QoS property will enable the quality-of-service features of the - // basesink which gather statistics about the real-time performance - // of the clock synchronisation. For each sample received in the sink, - // statistics are gathered and a QOS event is sent upstream with - // these numbers. This information can then be used by upstream - // elements to reduce their processing rate, for example. - if(!gst_base_sink_is_qos_enabled(GST_BASE_SINK(gst_appsink_))) - gst_base_sink_set_qos_enabled(GST_BASE_SINK(gst_appsink_), true); - - GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(gst_playbin_)); - if (!bus) { - LOG(ERROR) << "GStreamer bus creation failed"; - HandleError(MediaPlayerTizen::NetworkStateDecodeError); - return; - } -#if GST_VERSION_MAJOR == 1 - gst_bus_set_sync_handler( - bus, (GstBusSyncHandler)gst_pipeline_message_cb, this, NULL); -#else - gst_bus_set_sync_handler( - bus, (GstBusSyncHandler)gst_pipeline_message_cb, this); -#endif - gst_object_unref (bus); - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - PrepareForVideoSink(); -#else - PrepareForVideoFrame(); -#endif - - g_object_set(G_OBJECT(gst_playbin_), kPropertyVolume, volume_, NULL); - g_object_set( - G_OBJECT(gst_playbin_), kPropertyUri, url_.spec().c_str(), NULL); - - if (gst_element_set_state( - gst_playbin_, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) - LOG(ERROR) << "GStreamer state change failed"; - - manager()->OnReadyStateChange( - GetPlayerId(), MediaPlayerTizen::ReadyStateHaveEnoughData); - manager()->OnNetworkStateChange( - GetPlayerId(), MediaPlayerTizen::NetworkStateLoaded); - - if(url_.SchemeIsFile()) - is_file_url_ = true; - } else { - if (gst_playbin_) { - gst_object_unref(gst_playbin_); - gst_playbin_ = NULL; - } - if(gst_appsink_) { - gst_object_unref(gst_appsink_); - gst_appsink_ = NULL; - } - LOG(ERROR) << "Unable to create GStreamer elements"; - HandleError(MediaPlayerTizen::NetworkStateDecodeError); - } - } else { - LOG(ERROR) << "Unable to initialize GST"; - HandleError(MediaPlayerTizen::NetworkStateDecodeError); - } -} - -MediaPlayerBridgeGstreamer::~MediaPlayerBridgeGstreamer() { - VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); -} - -void MediaPlayerBridgeGstreamer::Destroy() { - VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); - if (IsPlayerDestructing()) - return; - - destructing_ = true; - Release(); - main_loop_->DeleteSoon(FROM_HERE, this); -} - -void MediaPlayerBridgeGstreamer::Play() { - VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); - if (!gst_playbin_) - return; - if (error_occured_ || is_end_reached_) - return; - if (playback_rate_ == 0.0) { - is_paused_ = false; - return; - } - if (gst_element_set_state( - gst_playbin_, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { - LOG(ERROR) << "GStreamer state change failed in PLAY"; - return; - } - -#if defined(OS_TIZEN_MOBILE) && (defined(TIZEN_V_2_3) || defined(TIZEN_V_2_4)) - if (device_power_request_lock(POWER_LOCK_DISPLAY, 0) != DEVICE_ERROR_NONE) - LOG(ERROR) << "|device_power_request_lock| request failed"; -#endif - - StartCurrentTimeUpdateTimer(); - is_paused_ = false; - is_end_reached_ = false; -} - -void MediaPlayerBridgeGstreamer::Pause(bool is_media_related_action) { - VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); - if (!gst_playbin_) - return; - if (error_occured_) - return; - if (gst_element_set_state( - gst_playbin_, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) { - LOG(ERROR) << "GStreamer state change failed in PAUSE"; - return; - } - -#if defined(OS_TIZEN_MOBILE) && (defined(TIZEN_V_2_3) || defined(TIZEN_V_2_4)) - if (device_power_release_lock(POWER_LOCK_DISPLAY) != DEVICE_ERROR_NONE) - LOG(ERROR) << "|device_power_release_lock| request failed"; -#endif - - StopCurrentTimeUpdateTimer(); - is_paused_ = true; -} - -void MediaPlayerBridgeGstreamer::SetRate(double rate) { - VLOG(1) << __FUNCTION__ << "Rate (" << rate << ")"; - if (!gst_playbin_) - return; - if (error_occured_) - return; - if (playback_rate_ == rate) - return; - if (is_live_stream_) - return; - - GstState state = GST_STATE_NULL; - GstState pending = GST_STATE_NULL; - gst_element_get_state(gst_playbin_, &state, &pending, 0); - if ((state != GST_STATE_PLAYING && state != GST_STATE_PAUSED) - || (pending == GST_STATE_PAUSED)) - return; - if (rate == 0.0) { - playback_rate_ = rate; - Pause(true); - return; - } - - // If rate was zero and requested rate is non-zero, change the paused state - if(playback_rate_ == 0.0 && rate != 0.0) { - Play(); - StartCurrentTimeUpdateTimer(); - } - - double current_position = GetCurrentTime() * GST_SECOND; - - if (rate < 0 && current_position == 0.0f) - current_position = -1.0f; - if (SeekTo( - current_position, rate, - static_cast(GST_SEEK_FLAG_FLUSH))) { - - // FIXME: Is is required to mute at abnormal playback rate? - playback_rate_ = rate; - } else { - LOG(ERROR) << "Setting Rate " << rate << " failed"; - HandleError(MediaPlayerTizen::NetworkStateDecodeError); - } -} - -void MediaPlayerBridgeGstreamer::Seek(const double time) { - VLOG(1) << __FUNCTION__ << "Time (" << time<< ")"; - - if (IsPlayerDestructing()) - return; - - if (!gst_playbin_ || error_occured_ || is_live_stream_ || - time == GetCurrentTime()) { - main_loop_->PostTask(FROM_HERE, base::Bind( - &MediaPlayerBridgeGstreamer::OnTimeChanged, base::Unretained(this))); - return; - } - - GstState state = GST_STATE_NULL; - GstStateChangeReturn ret = gst_element_get_state( - gst_playbin_, &state, NULL, 250 * GST_NSECOND); - if (ret == GST_STATE_CHANGE_FAILURE || ret == GST_STATE_CHANGE_NO_PREROLL) { - LOG(ERROR) << "Cannot seek in " - << gst_element_state_change_return_get_name(ret) << " state"; - return; - } - - StopCurrentTimeUpdateTimer(); - if (SeekTo( - ConvertToGstClockTime(time), playback_rate_, static_cast - (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE))) { - UpdateSeekState(true); - seek_duration_ = time; - is_end_reached_ = time != duration_ ? false : true; - manager()->OnTimeUpdate(GetPlayerId(), time); - if (!is_paused_) - StartCurrentTimeUpdateTimer(); - } else { - LOG(ERROR) << "MediaPlayerBridgeGstreamer::" << __FUNCTION__<<": Failed!"; - manager()->OnTimeUpdate(GetPlayerId(), GetCurrentTime()); - manager()->OnTimeChanged(GetPlayerId()); - } -} - -bool MediaPlayerBridgeGstreamer::SeekTo( - gint64 position, - float rate, - GstSeekFlags seekType) { - gint64 startTime = 0, endTime = 0; - if (rate > 0) { - startTime = position; - endTime = GST_CLOCK_TIME_NONE; - } else { - startTime = 0; - // If we are at beginning of media, start from the end to - // avoid immediate EOS. - if (position < 0) - endTime = static_cast(GetCurrentTime() * GST_SECOND); - else - endTime = position; - } - - return gst_element_seek(gst_playbin_, rate, GST_FORMAT_TIME, seekType, - GST_SEEK_TYPE_SET, startTime, GST_SEEK_TYPE_SET, endTime); -} - -void MediaPlayerBridgeGstreamer::Release() { - VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); - StopCurrentTimeUpdateTimer(); - StopBufferingUpdateTimer(); - if (gst_playbin_) { - GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(gst_playbin_)); - if (bus) { - g_signal_handlers_disconnect_by_func( - bus, reinterpret_cast(gst_pipeline_message_cb), this); -#if GST_VERSION_MAJOR == 1 - gst_bus_set_sync_handler(bus, NULL, NULL, NULL); -#else - gst_bus_set_sync_handler(bus, NULL, NULL); -#endif - gst_object_unref(bus); - } - - gst_element_set_state(gst_playbin_, GST_STATE_NULL); - gst_object_unref(gst_playbin_); - gst_playbin_ = NULL; - gst_appsink_ = NULL; - } -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - if (m_damage) { - ecore_x_damage_free(m_damage); - m_damage = 0; - } - if (m_damageHandler) { - ecore_event_handler_del(m_damageHandler); - m_damageHandler = NULL; - } - if (efl_pixmap_.get()) { - efl_pixmap_ = NULL; - } -#endif -} - -void MediaPlayerBridgeGstreamer::SetVolume(double volume) { - g_object_set(G_OBJECT(gst_playbin_), kPropertyVolume, volume, NULL); -} - -void MediaPlayerBridgeGstreamer::UpdateMediaType() { - int audio_stream_count = 0; - int video_stream_count = 0; - int text_stream_count = 0; - - g_object_get( - G_OBJECT(gst_playbin_), kPropertyAudioStream, &audio_stream_count, NULL); - g_object_get( - G_OBJECT(gst_playbin_), kPropertyVideoStream, &video_stream_count, NULL); - g_object_get( - G_OBJECT(gst_playbin_), kPropertyTextStream, &text_stream_count, NULL); - media_type_ = ((audio_stream_count ? MEDIA_AUDIO_MASK : 0) | - (video_stream_count ? MEDIA_VIDEO_MASK : 0)); - - // For Video-Sink Implementation we won't be getting Prepare-xid if we have - // only audio. - if (is_pixmap_used_ && video_stream_count == 0) - manager()->OnMediaDataChange( - GetPlayerId(), video_format_, gst_height_, gst_width_, media_type_); -} - -void MediaPlayerBridgeGstreamer::UpdateDuration() { - if (error_occured_) - return; - - gint64 duration = 0; - GstFormat format = GST_FORMAT_TIME; -#if GST_VERSION_MAJOR == 1 - gst_element_query_duration(gst_playbin_, format, &duration); -#else - gst_element_query_duration(gst_playbin_, &format, &duration); -#endif - duration_ = ConvertNanoSecondsToSeconds(duration); - manager()->OnDurationChange(GetPlayerId(), duration_); - // No need to sample 'local file'. Update buffered percentage. - if(is_file_url_) { - std::vector buffer_range; - media::MediaPlayerTizen::TimeRanges range; - range.start = 0; - range.end = duration_ * base::Time::kMicrosecondsPerSecond; - buffer_range.push_back(range); - manager()->OnBufferUpdate(GetPlayerId(), buffer_range); - } -} - -double MediaPlayerBridgeGstreamer::GetCurrentTime() { - if (error_occured_) - return 0.0; - - gint64 current_time = 0; - GstFormat format = GST_FORMAT_TIME; - - if (is_end_reached_) { - // Position queries on a null pipeline return 0. If we're at - // the end of the stream the pipeline is null but we want to - // report either the seek time or the duration because this is - // what the Media element spec expects us to do. - if (is_seeking_) - return seek_duration_; - - // Workaround for - // https://bugzilla.gnome.org/show_bug.cgi?id=639941 In GStreamer - // 0.10.35 basesink reports wrong duration in case of EOS and - // negative playback rate. There's no upstream accepted patch for - // this bug yet, hence this temporary workaround. - if (playback_rate_ < 0) - return 0.0f; - if (duration_) - return duration_; - - // FIXME: Should null be sent here? - } - -#if GST_VERSION_MAJOR == 1 - gst_element_query_position(gst_playbin_, format, ¤t_time); -#else - gst_element_query_position(gst_playbin_, &format, ¤t_time); -#endif - return ConvertNanoSecondsToSeconds(current_time); -} - -void MediaPlayerBridgeGstreamer::OnCurrentTimeUpdateTimerFired() { - manager()->OnTimeUpdate(GetPlayerId(), GetCurrentTime()); -} - -void MediaPlayerBridgeGstreamer::StartCurrentTimeUpdateTimer() { - if (!current_time_update_timer_.IsRunning()) { - current_time_update_timer_.Start( - FROM_HERE, - base::TimeDelta::FromMilliseconds(kDurationUpdateInterval), - this, &MediaPlayerBridgeGstreamer::OnCurrentTimeUpdateTimerFired); - } -} - -void MediaPlayerBridgeGstreamer::StopCurrentTimeUpdateTimer() { - if (current_time_update_timer_.IsRunning()) - current_time_update_timer_.Stop(); -} - -void MediaPlayerBridgeGstreamer::OnBufferingUpdateTimerFired() { - if (IsPlayerDestructing()) - return; - GetBufferedTimeRanges(); -} - -void MediaPlayerBridgeGstreamer::StartBufferingUpdateTimer() { - if (!buffering_update_timer_.IsRunning()) { - buffering_update_timer_.Start( - FROM_HERE, - base::TimeDelta::FromMilliseconds(kDurationUpdateInterval), - this, &MediaPlayerBridgeGstreamer::OnBufferingUpdateTimerFired); - } -} - -void MediaPlayerBridgeGstreamer::StopBufferingUpdateTimer() { - if (buffering_update_timer_.IsRunning()) - buffering_update_timer_.Stop(); -} - -#if GST_VERSION_MAJOR == 1 -GstSample* MediaPlayerBridgeGstreamer::PullSample() { - return gst_app_sink_pull_sample(GST_APP_SINK(gst_appsink_)); -} - -void MediaPlayerBridgeGstreamer::SampleReady(GstSample* sample) { - GstMapInfo map; - GstBuffer* buffer = gst_sample_get_buffer(sample); - - if (!gst_buffer_map(buffer, &map, GST_MAP_READ)) { - LOG (ERROR) << "Sample contains invalid or no info!"; - return; - } - - if (!gst_width_ || !gst_height_) - GetFrameDetails(); - - base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds( - GST_BUFFER_TIMESTAMP(buffer) / base::Time::kNanosecondsPerMicrosecond); - - if (video_format_ == GST_VIDEO_SN12) - shared_memory_size = (bufsize_sn12_); - else - shared_memory_size = (map.size); - - if (!shared_memory.CreateAndMapAnonymous(shared_memory_size)) { - LOG (ERROR) << "Shared Memory creation failed."; - gst_buffer_unmap(buffer, &map); - gst_sample_unref(sample); - return; - } - if (!shared_memory.ShareToProcess( - base::Process::Current().Handle(), &foreign_memory_handle)) { - LOG (ERROR) << "Shared Memory handle could not be obtained"; - shared_memory.Close(); - gst_buffer_unmap(buffer, &map); - gst_sample_unref(sample); - return; - } - memcpy(shared_memory.memory(), map.data, shared_memory_size); - manager()->OnNewFrameAvailable( - GetPlayerId(), foreign_memory_handle, shared_memory_size, timestamp); - - shared_memory.Close(); - gst_buffer_unmap(buffer, &map); - gst_sample_unref(sample); -} -#else -GstBuffer* MediaPlayerBridgeGstreamer::PullSample() { - return gst_app_sink_pull_buffer(GST_APP_SINK(gst_appsink_)); -} - -void MediaPlayerBridgeGstreamer::SampleReady( - const GstBuffer* buffer) { - if (!GST_BUFFER_DATA(buffer) || !GST_BUFFER_SIZE(buffer)) - return; - - if (!gst_width_ || !gst_height_) - GetFrameDetails(); - // FIXME: Cross check the end results. - - base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds( - GST_BUFFER_TIMESTAMP(buffer) / base::Time::kNanosecondsPerMicrosecond); - - uint8* buffer_data = GST_BUFFER_DATA(buffer); - gsize buffer_size = GST_BUFFER_SIZE(buffer); - if (video_format_ == GST_VIDEO_SN12) { - shared_memory_size = (bufsize_sn12_); - } else { - shared_memory_size = (buffer_size); - } - - if (!shared_memory.CreateAndMapAnonymous(shared_memory_size)) { - LOG (ERROR) << "Shared Memory creation failed."; - gst_buffer_unref(GST_BUFFER(buffer)); - return; - } - if (!shared_memory.ShareToProcess( - base::Process::Current().Handle(), &foreign_memory_handle)) { - LOG (ERROR) << "Shared Memory handle could not be obtained"; - shared_memory.Close(); - gst_buffer_unref(GST_BUFFER(buffer)); - return; - } - - memcpy(shared_memory.memory(), buffer_data, shared_memory_size); - manager()->OnNewFrameAvailable( - GetPlayerId(), foreign_memory_handle, shared_memory_size, timestamp); - - shared_memory.Close(); - gst_buffer_unref(GST_BUFFER(buffer)); -} -#endif - -// Updates networkState and ReadyState based on buffering percentage. -void MediaPlayerBridgeGstreamer::ProcessBufferingStats(GstMessage* message) { - if (IsPlayerDestructing()) - return; - - gst_message_parse_buffering(message, &buffered_); - main_loop_->PostTask(FROM_HERE, base::Bind( - &MediaPlayerBridgeGstreamer::OnUpdateStates, base::Unretained(this))); -} - -// To Update Buffered Ranges for Media Playback -void MediaPlayerBridgeGstreamer::GetBufferedTimeRanges() { - GstQuery *query = NULL; - gboolean result = false; - media::Ranges time_ranges; - std::vector buffer_range; - query = gst_query_new_buffering (GST_FORMAT_PERCENT); - result = gst_element_query(gst_playbin_, query); - if (result) { - gint n_ranges = 0, range = 0; - n_ranges = gst_query_get_n_buffering_ranges(query); - for (range = 0; range < n_ranges; range++) { - gint64 start = 0, stop = 0; - gst_query_parse_nth_buffering_range(query, range, &start, &stop); - media::MediaPlayerTizen::TimeRanges b_range; - -#if GST_VERSION_MAJOR == 1 - if ((start == 0 || is_end_reached_) && - stop == GST_FORMAT_PERCENT_MAX) - StopBufferingUpdateTimer(); - - b_range.start = start * duration_; - b_range.end = stop * duration_; -#else - // Stop the Timer on Buffer completion - if(start == 0 && stop == 100) - StopBufferingUpdateTimer(); - - // Parsed value is in percentage. Converted into time range - b_range.start = static_cast(start) * duration_ / 100 - * base::Time::kMicrosecondsPerSecond; - b_range.end = static_cast(stop) * duration_ / 100 - * base::Time::kMicrosecondsPerSecond; -#endif - - buffer_range.push_back(b_range); - } - manager()->OnBufferUpdate(GetPlayerId(), buffer_range); - } -} - -void MediaPlayerBridgeGstreamer::HandleMessage(GstMessage* message) { - if (IsPlayerDestructing()) - return; - - if (!strcmp(kPlaybinName, GST_MESSAGE_SRC_NAME(message))) - VLOG(1) << "MediaPlayerBridgeGstreamer::" << __FUNCTION__ - << " received from element " << GST_MESSAGE_SRC_NAME(message) - << " ID " << GetPlayerId(); - - const GstStructure* structure = gst_message_get_structure(message); - if (structure) { - const gchar* messageTypeName = gst_structure_get_name(structure); - - // Redirect messages are sent from elements, like qtdemux, to - // notify of the new location(s) of the media. - if (!g_strcmp0(messageTypeName, "redirect")) { - // FIXME: for changing media location - return; - } - } - - //FIXME: Add and handle all conditions - switch (GST_MESSAGE_TYPE(message)) { - case GST_MESSAGE_ERROR: - if (missing_plugins_) - break; - - StopBufferingUpdateTimer(); - GError* error; - gst_message_parse_error(message, &error, NULL); - MediaPlayerTizen::NetworkState network_state_error; - network_state_error = MediaPlayerTizen::NetworkStateEmpty; - if (error->code == GST_STREAM_ERROR_CODEC_NOT_FOUND - || error->code == GST_STREAM_ERROR_WRONG_TYPE - || error->code == GST_STREAM_ERROR_FAILED - || error->code == GST_CORE_ERROR_MISSING_PLUGIN - || error->code == GST_RESOURCE_ERROR_NOT_FOUND) { - network_state_error = MediaPlayerTizen::NetworkStateFormatError; - } else if (error->domain == GST_RESOURCE_ERROR) { - network_state_error = MediaPlayerTizen::NetworkStateNetworkError; - } else { - network_state_error = MediaPlayerTizen::NetworkStateDecodeError; - } - - LOG(ERROR) << "Error Message : " << error->message << " Recieved From : " - << GST_MESSAGE_SRC_NAME(message) - << ", and Blink Error Code = " << network_state_error; - g_error_free(error); - - HandleError(network_state_error); - break; - case GST_MESSAGE_EOS: - VLOG(1) << "Got GST_MESSAGE_EOS"; - main_loop_->PostTask(FROM_HERE, base::Bind( - &MediaPlayerBridgeGstreamer::OnPlaybackComplete, base::Unretained(this))); - break; - case GST_MESSAGE_ASYNC_DONE: - if (is_seeking_) { - UpdateSeekState(false); - main_loop_->PostTask(FROM_HERE, base::Bind( - &MediaPlayerBridgeGstreamer::OnTimeChanged, base::Unretained(this))); - } - - // Without |audio-sink| for audio tracks no preroll message is received. To - // update track details |PrerollComplete| is called. For Video tracks, - // preroll message is received long before control reaches here. - if (!is_prerolled_) - PrerollComplete(); - break; - case GST_MESSAGE_STATE_CHANGED: - if (strcmp(kPlaybinName, GST_MESSAGE_SRC_NAME(message))) - break; - - main_loop_->PostTask(FROM_HERE, base::Bind( - &MediaPlayerBridgeGstreamer::OnUpdateStates, base::Unretained(this))); - break; - case GST_MESSAGE_BUFFERING: - ProcessBufferingStats(message); - break; - case GST_MESSAGE_ELEMENT: - if (gst_is_missing_plugin_message(message)) { - gchar* detail = gst_missing_plugin_message_get_installer_detail(message); - gchar* detailArray[2] = {detail, 0}; - GstInstallPluginsReturn result = gst_install_plugins_async( - detailArray, 0, on_gst_installer_result_function, this); - missing_plugins_ = result == GST_INSTALL_PLUGINS_STARTED_OK; - g_free(detail); - } - - //gst_message_has_name (msg, "prepare-window-handle") -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - if (!IsXWindowHadleSet() && -#if GST_VERSION_MAJOR == 1 - gst_is_video_overlay_prepare_window_handle_message(message)) { -#else - gst_structure_has_name(message->structure, "prepare-xid")) { -#endif - LOG(INFO) << "Received message : Video overlay prepared"; - XWindowIdPrepared(message); - gst_message_unref(message); - return; - } -#endif - break; - default: - LOG(ERROR) << "Unhandled GStreamer message type: " - << GST_MESSAGE_TYPE_NAME(message); - break; - } -} - -void MediaPlayerBridgeGstreamer::HandlePluginInstallerResult( - GstInstallPluginsReturn result) { - missing_plugins_ = false; - if (result == GST_INSTALL_PLUGINS_SUCCESS) { - // FIXME: CAN CAUSE DEADLOCK? - gst_element_set_state(gst_playbin_, GST_STATE_READY); - gst_element_set_state(gst_playbin_, GST_STATE_PAUSED); - } else { - LOG(ERROR) << "GST Plugin Installation failed"; - HandleError(MediaPlayerTizen::NetworkStateDecodeError); - } -} - -void MediaPlayerBridgeGstreamer::UpdateStates() { - if (IsPlayerDestructing()) - return; - - if (error_occured_) - return; - - GstState state = GST_STATE_NULL; - GstState pending = GST_STATE_NULL; - GstStateChangeReturn ret = gst_element_get_state( - gst_playbin_, &state, &pending, 250 * GST_NSECOND); - - VLOG(1) << "MediaPlayerBridgeGstreamer::" - << __FUNCTION__ - << " GstStateChangeReturn: " - << gst_element_state_change_return_get_name(ret) - << " state: " - << gst_element_state_get_name(state) - << " pending: " - << gst_element_state_get_name(pending) - << " ID " << GetPlayerId(); - - // FIXME: Handle all state changes - switch (ret) { - case GST_STATE_CHANGE_SUCCESS: - if (!duration_) - UpdateDuration(); - - switch (state) { - case GST_STATE_NULL: - manager()->OnReadyStateChange( - GetPlayerId(), MediaPlayerTizen::ReadyStateHaveNothing); - manager()->OnNetworkStateChange( - GetPlayerId(), MediaPlayerTizen::NetworkStateEmpty); - break; - case GST_STATE_READY: - manager()->OnReadyStateChange( - GetPlayerId(), MediaPlayerTizen::ReadyStateHaveMetadata); - manager()->OnNetworkStateChange( - GetPlayerId(), MediaPlayerTizen::NetworkStateEmpty); - break; - case GST_STATE_PAUSED: - case GST_STATE_PLAYING: - if (!is_file_url_) - StartBufferingUpdateTimer(); - - VLOG(1) << "state " << gst_element_state_get_name(state) - << " buffered_ " << buffered_ - << " is_file_url_ " << is_file_url_ - << " is_paused_ " << is_paused_ - << " is_seeking_ " << is_seeking_; - - if (buffered_ == 100 || is_file_url_) { - if (state == GST_STATE_PAUSED && !is_paused_) { - if (gst_element_set_state(gst_playbin_, GST_STATE_PLAYING) - == GST_STATE_CHANGE_FAILURE) - LOG(ERROR) << "GStreamer state change failed"; - } - - // FIXME: On rapid playback on PIANO Widget, there are instences - // when 'ASYNC-DONE' message is not received on replay. - if (is_seeking_ && state == GST_STATE_PLAYING) { - LOG(ERROR) << "PLAYING state changed on seek"; - UpdateSeekState(false); - main_loop_->PostTask(FROM_HERE, - base::Bind(&MediaPlayerBridgeGstreamer::OnTimeChanged, - base::Unretained(this))); - } - manager()->OnReadyStateChange( - GetPlayerId(), MediaPlayerTizen::ReadyStateHaveEnoughData); - manager()->OnNetworkStateChange( - GetPlayerId(), MediaPlayerTizen::NetworkStateLoaded); - } else { - if (state == GST_STATE_PLAYING) { - if (gst_element_set_state(gst_playbin_, GST_STATE_PAUSED) - == GST_STATE_CHANGE_FAILURE) - LOG(ERROR) << "GStreamer state change failed"; - manager()->OnReadyStateChange( - GetPlayerId(), MediaPlayerTizen::ReadyStateHaveCurrentData); - manager()->OnNetworkStateChange( - GetPlayerId(), MediaPlayerTizen::NetworkStateLoading); - } - } - break; - default: - LOG(ERROR) << "GStreamer unhandled state " - << gst_element_state_get_name(state); - break; - } - break; - case GST_STATE_CHANGE_ASYNC: - // FIXME: For live stream. - break; - case GST_STATE_CHANGE_FAILURE: - LOG(ERROR) << "Failure: State: " - << gst_element_state_get_name(state) - << " pending: " - << gst_element_state_get_name(pending); - HandleError(MediaPlayerTizen::NetworkStateDecodeError); - break; - case GST_STATE_CHANGE_NO_PREROLL: - if (state == GST_STATE_READY) { - manager()->OnReadyStateChange( - GetPlayerId(), MediaPlayerTizen::ReadyStateHaveNothing); - } else if (state == GST_STATE_PAUSED) { - manager()->OnReadyStateChange( - GetPlayerId(), MediaPlayerTizen::ReadyStateHaveEnoughData); - is_paused_ = true; - is_live_stream_ = true; - } else if (state == GST_STATE_PLAYING) { - is_paused_ = false; - } - manager()->OnNetworkStateChange( - GetPlayerId(), MediaPlayerTizen::NetworkStateLoading); - break; - default: - LOG(ERROR) << "Unhandled return type: " << ret; - break; - } -} - -void MediaPlayerBridgeGstreamer::FrameReady( - const scoped_refptr& frame) { -} - -void MediaPlayerBridgeGstreamer::GetFrameDetails() { -#if GST_VERSION_MAJOR == 1 - GstSample* sample = gst_app_sink_pull_preroll(GST_APP_SINK(gst_appsink_)); - if (!sample) - return; - - GstCaps* caps = gst_sample_get_caps(sample); - if (!caps) - return; - - GstVideoInfo vi; - gst_video_info_from_caps(&vi, caps); - - gst_width_ = GST_VIDEO_INFO_WIDTH(&vi); - gst_height_ = GST_VIDEO_INFO_HEIGHT(&vi); - switch(GST_VIDEO_INFO_FORMAT(&vi)) { - case GST_VIDEO_FORMAT_I420:{ - video_format_ = GST_MAKE_FOURCC('I','4','2','0'); - break; - } - case GST_VIDEO_FORMAT_NV12:{ - video_format_ = GST_MAKE_FOURCC('N','V','1','2'); - break; - } - default: - LOG(ERROR) << "Unknown format : " << GST_VIDEO_INFO_FORMAT(&vi); - break; - } -#else - GstBuffer* sample = gst_app_sink_pull_preroll(GST_APP_SINK(gst_appsink_)); - if (!sample) - return; - - GstCaps* caps = gst_buffer_get_caps(GST_BUFFER(sample)); - if (!caps) - return; - - const GstStructure* str = gst_caps_get_structure(caps, 0); - gst_caps_unref(caps); - if (!str) - return; - - if (!gst_structure_get_int(str, "width", &gst_width_) || - !gst_structure_get_int(str, "height", &gst_height_) || - !gst_structure_get_fourcc(str, "format", &video_format_)) - LOG(ERROR) << "Pre-roll buffer info could not be obtained"; -#endif - - // Need to update frame details before sending sample. - manager()->OnMediaDataChange( - GetPlayerId(), static_cast(video_format_), - gst_height_, gst_width_, media_type_); - - if (video_format_ == GST_VIDEO_SN12) { - uint tile_w_align = ((gst_width_ - 1) / SN12_TILE_WIDTH + 2) & ~1; - bufsize_sn12_ = SN12_TILE_SIZE * tile_w_align * ((gst_height_ - 1) / - SN12_TILE_HEIGHT + 1) + (((gst_height_ + 1) & ~1) / 2) * tile_w_align * - SN12_TILE_WIDTH; - } - - SampleReady(sample); -} - -// FIXME: Works well for video playback. Do the same for /consider audio -// prerolling. -void MediaPlayerBridgeGstreamer::PrerollComplete() { - if(!is_pixmap_used_) { - UpdateMediaType(); - if (media_type_ & MEDIA_VIDEO_MASK) - GetFrameDetails(); - else - manager()->OnMediaDataChange( - GetPlayerId(), static_cast(video_format_), - gst_height_, gst_width_, media_type_); - - VLOG(1) << "MediaPlayerBridgeGstreamer::PrerollComplete." - << " video_format " << video_format_ - << " width " << gst_width_ - << " height " << gst_height_ - << " media_type " << media_type_; - } else { - UpdateMediaType(); - } - is_prerolled_ = true; -} - -void MediaPlayerBridgeGstreamer::OnPlaybackComplete() { - VLOG(1) << "OnPlaybackComplete" << " ID " << GetPlayerId(); - is_end_reached_ = true; - -#if defined(OS_TIZEN_MOBILE) && (defined(TIZEN_V_2_3) || defined(TIZEN_V_2_4)) - if (device_power_release_lock(POWER_LOCK_DISPLAY) != DEVICE_ERROR_NONE) - LOG(ERROR) << "|device_power_release_lock| request failed"; -#endif - - StopCurrentTimeUpdateTimer(); - manager()->OnTimeUpdate(GetPlayerId(), GetCurrentTime()); - manager()->OnTimeChanged(GetPlayerId()); -} - -void MediaPlayerBridgeGstreamer::UpdateSeekState(bool state) { - is_seeking_ = state; -} - -void MediaPlayerBridgeGstreamer::OnTimeChanged() { - VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); - DCHECK(main_loop_->BelongsToCurrentThread()); - manager()->OnTimeChanged(GetPlayerId()); -} - -void MediaPlayerBridgeGstreamer::OnUpdateStates() { - VLOG(1) << __FUNCTION__ << " : Player Id = " << GetPlayerId(); - DCHECK(main_loop_->BelongsToCurrentThread()); - UpdateStates(); -} - -GstElement* MediaPlayerBridgeGstreamer::GetVideoSink() { -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - is_pixmap_used_ = true; - return gst_element_factory_make("xvimagesink", kVideoSink); -#else - is_pixmap_used_ = false; - return gst_element_factory_make("appsink", kVideoSink); -#endif -} - -void MediaPlayerBridgeGstreamer::PrepareForVideoFrame() { - VLOG(1) << "MediaElement using shared memory to pass the frames"; - int flags = 0; - g_object_get(gst_playbin_, "flags", &flags, NULL); - flags = GST_PLAY_FLAG_NATIVE_VIDEO | GST_PLAY_FLAG_NATIVE_AUDIO - | GST_PLAY_FLAG_DOWNLOAD; -#ifdef OS_TIZEN_TV - flags |= GST_PLAY_FLAG_NATIVE_VIDEO | GST_PLAY_FLAG_NATIVE_AUDIO; - flags &= ~GST_PLAY_FLAG_VIDEO & ~GST_PLAY_FLAG_AUDIO & - ~GST_PLAY_FLAG_DEINTERLACE & ~GST_PLAY_FLAG_SOFT_COLORBALANCE; -#if defined(TIZEN_V_3_0) - flags |= GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_NATIVE_VIDEO; - flags &= ~GST_PLAY_FLAG_NATIVE_AUDIO; -#endif -#endif - g_object_set(gst_playbin_, "flags", flags, NULL); -#if GST_VERSION_MAJOR == 1 - GstAppSinkCallbacks callbacks = {on_gst_appsink_eos, on_gst_appsink_preroll, - on_gst_appsink_sample}; -#else - GstAppSinkCallbacks callbacks = {on_gst_appsink_eos, - on_gst_appsink_preroll, - on_gst_appsink_sample, - NULL, - {NULL, NULL, NULL}}; -#endif - gst_app_sink_set_callbacks(GST_APP_SINK(gst_appsink_), &callbacks, - this, NULL); - - g_object_set(G_OBJECT(gst_playbin_), kPropertyBufferSize, - kPreloadBufferSize, NULL); - g_object_set(G_OBJECT(gst_appsink_), kPropertyMaxBuffers, - (guint)kMaxBuffer, NULL); -} - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -void MediaPlayerBridgeGstreamer::PrepareForVideoSink() { - VLOG(1) << "MediaElement Backed by Video-Sink (xvimagesink)"; - int flags = 0; - g_object_get(gst_playbin_, "flags", &flags, NULL); - flags |= GST_PLAY_FLAG_NATIVE_VIDEO; - flags &= ~GST_PLAY_FLAG_TEXT; - g_object_set(gst_playbin_, "flags", flags, NULL); -} - -void MediaPlayerBridgeGstreamer::XWindowIdPrepared(GstMessage* message) { - // It is called just once after video src is set. -#if GST_VERSION_MAJOR == 1 - const GstStructure* structure = gst_message_get_structure(message); - gst_structure_get_int(structure, "video-width", &gst_width_); - gst_structure_get_int(structure, "video-height", &gst_height_); -#else - gst_structure_get_int(message->structure, "video-width", &gst_width_); - gst_structure_get_int(message->structure, "video-height", &gst_height_); -#endif - SetPixmap(); -} - -int MediaPlayerBridgeGstreamer::GetSurfaceID() const { - return pixmap_id_; -} - -void MediaPlayerBridgeGstreamer::SetPixmap() { - efl_pixmap_ = gfx::EflPixmap::Create(gfx::EflPixmap::SURFACE, gfx::Size( - gst_width_, gst_height_)); - if (!efl_pixmap_.get()) { - LOG(ERROR) << "gfx::EflPixmap::Create() failed to create Pixmap"; - return ; - } - pixmap_id_ = efl_pixmap_->GetId(); - g_object_set (gst_appsink_, "pixmap-id-callback", get_pixmap_id_cb, NULL); - g_object_set (gst_appsink_, "pixmap-id-callback-userdata", this, NULL); - - //Register to get notification from ecore for damage updates. - m_damage = ecore_x_damage_new( - pixmap_id_, ECORE_X_DAMAGE_REPORT_RAW_RECTANGLES); - m_damageHandler = ecore_event_handler_add( - ECORE_X_EVENT_DAMAGE_NOTIFY, notify_damage_updated_cb, this); - g_object_set(gst_appsink_, "rotate", DEGREE_0, NULL); - - // Passing NUL value for video_format. Its not required but - // |webmediaplayertizen| expects a value. - UpdateMediaType(); - manager()->OnMediaDataChange( - GetPlayerId(), video_format_, gst_height_, gst_width_, media_type_); -} - -void MediaPlayerBridgeGstreamer::PlatformSurfaceUpdated() { - gint64 current_time = 0; - GstFormat format = GST_FORMAT_TIME; -#if GST_VERSION_MAJOR == 1 - gst_element_query_position(gst_playbin_, format, ¤t_time); -#else - gst_element_query_position(gst_playbin_, &format, ¤t_time); -#endif - base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds( - current_time / base::Time::kNanosecondsPerMicrosecond); - manager()->OnPlatformSurfaceUpdated(GetPlayerId(), pixmap_id_, timestamp); -} -#endif - -void MediaPlayerBridgeGstreamer::HandleError( - media::MediaPlayerTizen::NetworkState state) { - LOG(ERROR) << "Error in MediaPlayerBridgeGstreamer::HandleError"; -#if defined(OS_TIZEN_MOBILE) && (defined(TIZEN_V_2_3) || defined(TIZEN_V_2_4)) - if (device_power_release_lock(POWER_LOCK_DISPLAY) != DEVICE_ERROR_NONE) - LOG(ERROR) << "|device_power_release_lock| request failed"; -#endif - - error_occured_ = true; - manager()->OnNetworkStateChange(GetPlayerId(), state); -} - -} // namespace media diff --git a/tizen_src/impl/media/base/tizen/media_player_bridge_gstreamer.h b/tizen_src/impl/media/base/tizen/media_player_bridge_gstreamer.h deleted file mode 100644 index 91bc7ab2f259..000000000000 --- a/tizen_src/impl/media/base/tizen/media_player_bridge_gstreamer.h +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MEDIA_TIZEN_MEDIA_PLAYER_BRIDGE_GSTREMEAR_H_ -#define MEDIA_TIZEN_MEDIA_PLAYER_BRIDGE_GSTREMEAR_H_ - -#include -#include -#include - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -#include -#include -#endif - -#include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" -#include "base/timer/timer.h" -#include "content/public/browser/browser_message_filter.h" -#include "media/base/ranges.h" -#include "media/base/tizen/media_player_tizen.h" -#include "media/base/video_frame.h" - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -#include "ui/gl/efl_pixmap.h" -#endif - -namespace media { - -class MEDIA_EXPORT MediaPlayerBridgeGstreamer - : public MediaPlayerTizen { - public: - MediaPlayerBridgeGstreamer( - int player_id, - const GURL& url, - double volume, - MediaPlayerManager* manager); - virtual ~MediaPlayerBridgeGstreamer(); - - // MediaPlayerTizen implementation. - virtual void Play() override; - virtual void Pause(bool is_media_related_action) override; - virtual void SetRate(double rate) override; - virtual void Seek(const double time) override; - virtual void SetVolume(double volume) override; - virtual double GetCurrentTime() override; - virtual void Destroy() override; - - // Error handling API - void HandleError(media::MediaPlayerTizen::NetworkState state); - - void HandleMessage(GstMessage* message); - void HandlePluginInstallerResult(GstInstallPluginsReturn result); -#if GST_VERSION_MAJOR == 1 - GstSample* PullSample(); - void SampleReady(GstSample* buffer); -#else - GstBuffer* PullSample(); - void SampleReady(const GstBuffer* buffer); -#endif - void PrerollComplete(); - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - void PlatformSurfaceUpdated(); - int GetSurfaceID() const; -#endif - - protected: - virtual void Release(); - - private: - // |duration_update_timer_| related - void OnCurrentTimeUpdateTimerFired(); - void StartCurrentTimeUpdateTimer(); - void StopCurrentTimeUpdateTimer(); - - // |Buffering_update_timer_| related - void OnBufferingUpdateTimerFired(); - void StartBufferingUpdateTimer(); - void StopBufferingUpdateTimer(); - - void UpdateStates(); - void OnUpdateStates(); - void UpdateDuration(); - void UpdateMediaType(); - void UpdateSeekState(bool state); - - void OnPlaybackComplete(); - void OnTimeChanged(); - - void FrameReady(const scoped_refptr& frame); - void GetFrameDetails(); - void ProcessBufferingStats(GstMessage* message); - void GetBufferedTimeRanges(); - bool SeekTo(gint64 position, float rate, GstSeekFlags seekType); - - GstElement* GetVideoSink(); - void PrepareForVideoFrame(); - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - void PrepareForVideoSink(); - void XWindowIdPrepared(GstMessage*); - bool IsXWindowHadleSet(){return pixmap_id_ ? true : false ;} - void SetPixmap(); -#endif - - private: - const scoped_refptr main_loop_; - GstElement* gst_playbin_; - GstElement* gst_appsink_; - GURL url_; - double volume_; - gint gst_width_; - gint gst_height_; - - bool is_prerolled_; - bool is_paused_; - double duration_; - double playback_rate_; - int buffered_; - guint32 video_format_; - - int media_type_; - bool is_live_stream_; - bool is_file_url_; - bool is_end_reached_ ; - bool is_seeking_ ; - bool is_seek_pending_ ; - double seek_duration_; - - bool error_occured_; - bool missing_plugins_; - bool is_pixmap_used_; - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - int pixmap_id_; - scoped_refptr efl_pixmap_; - Ecore_X_Damage m_damage; - Ecore_Event_Handler* m_damageHandler; -#endif - uint bufsize_sn12_; - - base::SharedMemory shared_memory; - uint32 shared_memory_size; - base::SharedMemoryHandle foreign_memory_handle; - - base::RepeatingTimer current_time_update_timer_; - base::RepeatingTimer buffering_update_timer_; - - DISALLOW_COPY_AND_ASSIGN(MediaPlayerBridgeGstreamer); -}; - -} // namespace media - -#endif // MEDIA_TIZEN_MEDIA_PLAYER_BRIDGE_GSTREMEAR_H_ diff --git a/tizen_src/impl/media/base/tizen/media_player_manager_tizen.h b/tizen_src/impl/media/base/tizen/media_player_manager_tizen.h deleted file mode 100644 index 5370ec852292..000000000000 --- a/tizen_src/impl/media/base/tizen/media_player_manager_tizen.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MEDIA_BASE_TIZEN_MEDIA_PLAYER_TIZEN_MANAGER_H_ -#define MEDIA_BASE_TIZEN_MEDIA_PLAYER_TIZEN_MANAGER_H_ - -#include - -#include "base/memory/shared_memory.h" -#include "media/base/tizen/media_player_tizen.h" - -namespace media { - -class MediaPlayerTizen; - -class MEDIA_EXPORT MediaPlayerManager { - public: - virtual ~MediaPlayerManager() { } - virtual MediaPlayerTizen* GetPlayer(int player_id) = 0; - - virtual void OnTimeChanged(int player_id) = 0; - virtual void OnTimeUpdate(int player_id, double current_time) = 0; - virtual void OnRequestSeek(int player_id, double seek_time) = 0; - virtual void OnPauseStateChange(int player_id, bool state) = 0; - virtual void OnSeekStateChange(int player_id, bool state) = 0; - virtual void OnBufferUpdate( - int player_id, - std::vector buffer_range) = 0; - virtual void OnDurationChange(int player_id, double duration) = 0; - virtual void OnReadyStateChange(int player_id, - MediaPlayerTizen::ReadyState state) = 0; - virtual void OnNetworkStateChange( - int player_id, - MediaPlayerTizen::NetworkState state) = 0; - virtual void OnMediaDataChange( - int player_id, - int format, - int height, - int width, - int media) = 0; - virtual void OnNewFrameAvailable( - int player_id, - base::SharedMemoryHandle handle, - uint32 length, - base::TimeDelta timestamp) = 0; -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - virtual void OnPlatformSurfaceUpdated( - int player_id, - int pixmap_id, - base::TimeDelta timestamp) = 0; -#endif -}; - -} // namespace media - -#endif // MEDIA_BASE_TIZEN_MEDIA_PLAYER_TIZEN_MANAGER_H_ \ No newline at end of file diff --git a/tizen_src/impl/media/base/tizen/media_player_tizen.h b/tizen_src/impl/media/base/tizen/media_player_tizen.h deleted file mode 100755 index ce7c3ac65a29..000000000000 --- a/tizen_src/impl/media/base/tizen/media_player_tizen.h +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MEDIA_TIZEN_MEDIA_PLAYER_TIZEN_H_ -#define MEDIA_TIZEN_MEDIA_PLAYER_TIZEN_H_ - -#include - -#include "base/basictypes.h" -#include "base/callback.h" -#include "base/time/time.h" -#include "content/common/media/tizen/media_player_messages_enums_tizen.h" -#include "media/base/media_export.h" -#include "url/gurl.h" - -namespace media { - -class MediaDrmBridge; -class MediaPlayerManager; - -// Error types for MediaErrorCB. -enum MediaErrorType { - MEDIA_ERROR_FORMAT, - MEDIA_ERROR_DECODE, - MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK, - MEDIA_ERROR_INVALID_CODE, -}; - -// media type masks -const int MEDIA_AUDIO_MASK = 0x02; -const int MEDIA_VIDEO_MASK = 0x01; - -class MEDIA_EXPORT MediaPlayerTizen{ - public: - // FIXME: Remove these enum and use webkit's - enum ReadyState { - ReadyStateHaveNothing, - ReadyStateHaveMetadata, - ReadyStateHaveCurrentData, - ReadyStateHaveFutureData, - ReadyStateHaveEnoughData, - }; - - enum NetworkState { - NetworkStateEmpty, - NetworkStateIdle, - NetworkStateLoading, - NetworkStateLoaded, - NetworkStateFormatError, - NetworkStateNetworkError, - NetworkStateDecodeError, - }; - - typedef struct range { - int64 start; - int64 end; - } TimeRanges; - - MediaPlayerTizen() { } - virtual ~MediaPlayerTizen() { } - - // Start playing the media. - virtual void Play() = 0; - - // To Pause from HTMLMediaElement, pass |false| as argument. - // Pass |true| as argument when buffer is low in case of MediaSource. - virtual void Pause(bool is_media_related_action) = 0; - - virtual void SetRate(double rate) = 0; - - // Seek to a particular position, based on renderer signaling actual seek - // with MediaPlayerHostMsg_Seek. If eventual success, OnSeekComplete() will be - // called. - virtual void Seek(const double time) = 0; - - // Set the player volume. - virtual void SetVolume(double volume) = 0; - - // Get the media information from the player. - virtual double GetCurrentTime() = 0; - - int GetPlayerId() { return player_id_; } - - bool IsPlayerDestructing() { return destructing_; } - - // Destroy this object when all messages for it are delivered - virtual void Destroy() = 0; - - protected: - // Release the player resources. - virtual void Release() = 0; - - MediaPlayerTizen(int player_id, MediaPlayerManager* manager) - : destructing_(false), player_id_(player_id), manager_(manager) { } - - MediaPlayerManager* manager() { return manager_; } - - bool destructing_; - - private: - // Player ID assigned to this player. - int player_id_; - - // Resource manager for all the media players. - MediaPlayerManager* manager_; - - DISALLOW_COPY_AND_ASSIGN(MediaPlayerTizen); -}; - -} // namespace media - -#endif // MEDIA_TIZEN_MEDIA_PLAYER_TIZEN_H_ diff --git a/tizen_src/impl/media/base/tizen/media_source_player_gstreamer.cc b/tizen_src/impl/media/base/tizen/media_source_player_gstreamer.cc deleted file mode 100644 index 0ee7f50740d6..000000000000 --- a/tizen_src/impl/media/base/tizen/media_source_player_gstreamer.cc +++ /dev/null @@ -1,1889 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "media/base/tizen/media_source_player_gstreamer.h" - -#include -#include -#include - -#include "base/process/process.h" -#include "media/base/tizen/media_player_manager_tizen.h" - -#if defined(OS_TIZEN_MOBILE) && (defined(TIZEN_V_2_3) || defined(TIZEN_V_2_4)) -#include -#endif - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -#if GST_VERSION_MAJOR == 1 -#include -#else -#include -#endif -#endif - -namespace { - -const uint32 GST_VIDEO_SN12 = GST_MAKE_FOURCC('S','N','1','2'); - -const uint SN12_TILE_WIDTH = 64; -const uint SN12_TILE_HEIGHT = 32; -const uint SN12_TILE_SIZE = SN12_TILE_WIDTH * SN12_TILE_HEIGHT; - -// Pipeline element name -const char* kPipelineName = "gst_pipeline"; - -// Update duration every 100ms. -const int kDurationUpdateInterval = 100; - -// For smooth playback, seeking will be done to I-Frame + kSixteenMilliSeconds -// Reason to choose kSixteenMilliSeconds is duration of each video frame at -// 60 fps video will be ~16 milliseconds. -const int64 kSixteenMilliSeconds = 16000000; - -const char *h264elements[] = { - "h264parse" -#if defined(OS_TIZEN_MOBILE) - , "avdec_h264" -#elif defined(OS_TIZEN_TV) -#if defined(TIZEN_V_3_0) - , "avdec_h264" -#else - , "omx_h264dec" -#endif -#else - , "ffdec_h264" -#endif -}; - -const char *aacelements[] = { - "aacparse" -#if defined(OS_TIZEN_MOBILE) - , "avdec_aac", "autoaudiosink" -#elif defined(OS_TIZEN_TV) -#if defined(TIZEN_V_3_0) - , "avdec_aac", "alsasink" -#else - , "omx_aacdec", "alsasink" -#endif -#else - , "faad", "autoaudiosink" -#endif -}; - -// FIXME: This is derived from command-line pipeline on desktop and mobile. -// Need to find the pipeline on TV. -// Also the connection might be different when converting it to code. -const char *mp3elements[] = { - "mpegaudioparse" -#if defined(OS_TIZEN_MOBILE) - , "avdec_mp3" -#else -#if defined(TIZEN_V_3_0) - , "avdec_mp3" -#else - , "ffdec_mp3" -#endif -#endif - ,"autoaudiosink" -}; - -const AudioCodecGstElementsMapping AudioMapping[] = { - {media::kCodecAAC, aacelements}, - {media::kCodecMP3, mp3elements}, - {media::kUnknownAudioCodec, NULL} -}; - -const VideoCodecGstElementsMapping VideoMapping[] = { - {media::kCodecH264, h264elements}, - {media::kUnknownVideoCodec, NULL} -}; - -GstClockTime ConvertToGstClockTime(double time) { - if (time < 0) { - LOG(ERROR) << "Invalid time:" << time << " Reset to 0"; - time = 0; - } - - // Extract the integer part of the time (seconds) and the fractional part - // (microseconds). Attempt to round the microseconds so no floating point - // precision is lost and we can perform an accurate seek. - double seconds; - double microSeconds = std::modf(time, &seconds) * 1000000; - GTimeVal timeValue; - timeValue.tv_sec = static_cast(seconds); - timeValue.tv_usec = static_cast(lround(microSeconds / 10) * 10); - return GST_TIMEVAL_TO_TIME(timeValue); -} - -double ConvertNanoSecondsToSeconds(int64 time) { - double seconds = static_cast(time) / - (base::Time::kNanosecondsPerSecond); - return seconds; -} - -} // namespace - -namespace media { - -static GstBusSyncReply gst_pipeline_message_cb( - GstBus* bus, - GstMessage* message, - gpointer user_data) { - MediaSourcePlayerGstreamer* player = - static_cast(user_data); - if (!player || player->IsPlayerDestructing()) - return GST_BUS_PASS; - - player->HandleMessage(message); - gst_message_unref(message); - return GST_BUS_DROP; -} - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -static Eina_Bool notify_damage_updated_cb( - void* user_data, - int type, - void* event) { - MediaSourcePlayerGstreamer* player = - static_cast(user_data); - if (!player || player->IsPlayerDestructing()) - return ECORE_CALLBACK_PASS_ON; - player->PlatformSurfaceUpdated(); - return ECORE_CALLBACK_PASS_ON; -} -#endif - -#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -static int get_pixmap_id_cb(void* user_data) { - MediaSourcePlayerGstreamer* player = - static_cast(user_data); - return player->GetSurfaceID(); -} -#endif - -static ASM_cb_result_t media_player_audio_session_event_source_pause( - ASM_event_sources_t event_source, - void* user_data) { - MediaPlayerTizen* player = - static_cast(user_data); - if (!player) { - return ASM_CB_RES_IGNORE; - } - - switch (event_source) { - case ASM_EVENT_SOURCE_CALL_START: - case ASM_EVENT_SOURCE_ALARM_START: - case ASM_EVENT_SOURCE_MEDIA: - case ASM_EVENT_SOURCE_EMERGENCY_START: - case ASM_EVENT_SOURCE_OTHER_PLAYER_APP: - case ASM_EVENT_SOURCE_RESOURCE_CONFLICT: - case ASM_EVENT_SOURCE_EARJACK_UNPLUG: - player->Pause(true); - return ASM_CB_RES_PAUSE; - default: - return ASM_CB_RES_NONE; - } -} - -static ASM_cb_result_t media_player_audio_session_event_source_play( - ASM_event_sources_t event_source, - void* user_data) { - MediaPlayerTizen* player = - static_cast(user_data); - if (!player) { - return ASM_CB_RES_IGNORE; - } - - switch (event_source) { - case ASM_EVENT_SOURCE_ALARM_END: - player->Play(); - return ASM_CB_RES_PLAYING; - default: - return ASM_CB_RES_NONE; - } -} - -static ASM_cb_result_t media_player_private_audio_session_notify_cb( - int, - ASM_event_sources_t event_source, - ASM_sound_commands_t command, - unsigned int, - void* user_data) { - if (command == ASM_COMMAND_STOP || command == ASM_COMMAND_PAUSE) - return media_player_audio_session_event_source_pause( - event_source, user_data); - if (command == ASM_COMMAND_PLAY || command == ASM_COMMAND_RESUME) - return media_player_audio_session_event_source_play( - event_source, user_data); - return ASM_CB_RES_NONE; -} -#endif - -static void on_gst_start_video_feed_cb( - GstAppSrc* pipeline, - guint size, - void *user_data) { - MediaSourcePlayerGstreamer* player = - static_cast(user_data); - if (!player || player->IsPlayerDestructing()) - return; - player->OnReadDemuxedData(media::DemuxerStream::VIDEO); - return ; -} - -static void on_gst_stop_video_feed_cb(GstAppSrc * pipeline,void *user_data) { - MediaSourcePlayerGstreamer* player = - static_cast(user_data); - if (!player || player->IsPlayerDestructing()) - return; - player->OnStopDemuxedData(media::DemuxerStream::VIDEO); -} - -static gboolean on_gst_seek_video_feed_cb( - GstAppSrc* pipeline, - guint64 offset, - void *user_data) { - - MediaSourcePlayerGstreamer* player = - static_cast(user_data); - if (!player || player->IsPlayerDestructing()) - return FALSE; - player->UpdateVideoSeekOffset(offset); - return TRUE; -} - -static GstFlowReturn on_gst_appsink_preroll( - GstAppSink* sink, - gpointer user_data) { - MediaSourcePlayerGstreamer* player = - static_cast(user_data); - if (!player || player->IsPlayerDestructing()) - return GST_FLOW_ERROR; - player->GetFrameDetails(); - return GST_FLOW_OK; -} - -static GstFlowReturn on_gst_appsink_sample( - GstAppSink* sink, - gpointer user_data) { - MediaSourcePlayerGstreamer* player = - static_cast(user_data); - if (!player || player->IsPlayerDestructing()) - return GST_FLOW_ERROR; - player->OnNewFrameAvailable(player->PullSample()); - return GST_FLOW_OK; -} - -gboolean on_gst_seek_audio_feed_cb( - GstAppSrc *pipeline, - guint64 offset, - void* user_data) { - MediaSourcePlayerGstreamer* player = - static_cast(user_data); - if (!player || player->IsPlayerDestructing()) - return FALSE; - player->UpdateAudioSeekOffset(offset); - return TRUE; -} - -static void on_gst_start_audio_feed_cb ( - GstAppSrc * pipeline, - guint size, - void* user_data) { - MediaSourcePlayerGstreamer* player = - static_cast(user_data); - if (!player || player->IsPlayerDestructing()) - return; - player->OnReadDemuxedData(media::DemuxerStream::AUDIO); -} - -static void on_gst_stop_audio_feed_cb(GstAppSrc* pipeline, void* user_data) { - MediaSourcePlayerGstreamer* player = - static_cast(user_data); - if (!player || player->IsPlayerDestructing()) - return; - player->OnStopDemuxedData(media::DemuxerStream::AUDIO); -} - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -static void on_video_sink_caps_changed_cb( - GObject* gobject, - GParamSpec* gparamspec, - void* user_data) { - MediaSourcePlayerGstreamer* player = - static_cast(user_data); - if (!player || player->IsPlayerDestructing()) - return; - player->OnVideoConfigsChanged(); -} -#endif - -// Generating Unique string from given width and height. -std::string ConvertWidthAndHeightToString(int width, int height) { - std::ostringstream width_stream, height_stream; - width_stream << width; - height_stream << height; - return width_stream.str() + "X" + height_stream.str(); -} - -MediaSourcePlayerGstreamer::MediaSourcePlayerGstreamer( - int player_id, - scoped_ptr demuxer, - MediaPlayerManager* manager) - : MediaPlayerTizen(player_id, manager), - demuxer_(demuxer.Pass()), - main_loop_(base::MessageLoopProxy::current()), -#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) - audio_session_manager_(AudioSessionManager::CreateAudioSessionManager()), -#endif - playing_(false), - weak_this_(this), -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - pixmap_id_(0), - efl_pixmap_(NULL), - m_damage(0), - m_damageHandler(0), -#endif - is_xwindow_handle_set_(false), - is_backed_by_pixmap(false), - pipeline_(NULL), - video_appsrc_(NULL), - video_parse_(NULL), - video_decoder_(NULL), - video_sink_(NULL), - audio_appsrc_(NULL), - audio_decoder_(NULL), - audio_sink_(NULL), - video_queue_(NULL), - audio_queue_(NULL), - audio_parse_(NULL), - audio_convert_(NULL), - audio_resampler_(NULL), - audio_volume_(NULL), - video_sink_pad_(NULL), - should_feed_audio_(true), - should_feed_video_(false), - gst_width_(0), - gst_height_(0), - video_format_(0), - media_type(0), - play_rate_(1.0f), - duration_(0), - is_paused_due_underflow_(false), - shared_memory_size(0), - buffered_(0), - is_paused_(false), - is_seeking_(false), - is_demuxer_seeking_(false), - audio_buffered_(0), - video_buffered_(0), - is_gst_pipeline_constructed_(false), - is_download_finished_(false), - is_end_reached_(false), - error_occured_(false), - raw_video_frame_size_(0), - video_seek_offset_(0), - audio_seek_offset_(0), - is_seeking_iframe_(false) { - demuxer_->Initialize(this); - audio_buffer_queue_.clear(); - video_buffer_queue_.clear(); -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - efl_pixmaps_map_.clear(); -#endif -#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) - if (!audio_session_manager_->RegisterAudioSessionManager( - MM_SESSION_TYPE_SHARE, - media_player_private_audio_session_notify_cb, this)) - return; -#endif -} - -MediaSourcePlayerGstreamer::~MediaSourcePlayerGstreamer() { - VLOG(1) << "MediaSourcePlayerGstreamer::" << __FUNCTION__ - << "Player ID:" << GetPlayerId(); -} - -void MediaSourcePlayerGstreamer::Destroy() { - if (IsPlayerDestructing()) - return; - - VLOG(1) << "MediaSourcePlayerGstreamer::" << __FUNCTION__ - << "Player ID:" << GetPlayerId(); - destructing_ = true; - Release(); - main_loop_->DeleteSoon(FROM_HERE, this); -} - -void MediaSourcePlayerGstreamer::Play() { - if (!pipeline_ || error_occured_) - return; - if (play_rate_ == 0.0) { - playing_ = true; - return; - } -#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) - if (!audio_session_manager_->SetSoundState(ASM_STATE_PLAYING)) - return; -#endif - VLOG(1) << "MediaSourcePlayerGstreamer::" << __FUNCTION__ - << "Player ID:" << GetPlayerId(); - -#if defined(OS_TIZEN_MOBILE) && (defined(TIZEN_V_2_3) || defined(TIZEN_V_2_4)) - if (device_power_wakeup(false) != DEVICE_ERROR_NONE) - LOG(ERROR) << "|device_power_wakeup| request failed"; - - if (device_power_request_lock(POWER_LOCK_DISPLAY, 0) != DEVICE_ERROR_NONE) - LOG(ERROR) << "|device_power_request_lock| request failed"; -#endif - - gst_element_set_state(pipeline_, GST_STATE_PLAYING); - StartCurrentTimeUpdateTimer(); - playing_ = true; - is_paused_due_underflow_ = false; -} - -void MediaSourcePlayerGstreamer::Pause(bool is_media_related_action) { - if (!pipeline_ || error_occured_) - return; - -#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) - if (!audio_session_manager_->SetSoundState(ASM_STATE_PAUSE)) - return; -#endif - - VLOG(1) << "MediaSourcePlayerGstreamer::" << __FUNCTION__; - gst_element_set_state(pipeline_, GST_STATE_PAUSED); - - StopCurrentTimeUpdateTimer(); - if (!is_media_related_action) { - -#if defined(OS_TIZEN_MOBILE) && (defined(TIZEN_V_2_3) || defined(TIZEN_V_2_4)) - if (device_power_release_lock(POWER_LOCK_DISPLAY) != DEVICE_ERROR_NONE) - LOG(ERROR) << "|device_power_release_lock| request failed"; -#endif - - is_paused_due_underflow_ = false; - playing_ = false; - } -} - -void MediaSourcePlayerGstreamer::SetRate(double rate) { - VLOG(1) << "MediaSourcePlayerGstreamer::" - << __FUNCTION__ << " : " << rate; - - if (play_rate_ == rate) - return; - - if (rate == 0.0) { - play_rate_ = rate; - Pause(true); - return; - } - - // If rate was zero and requested rate is non-zero, change the paused state - if(play_rate_ == 0.0 && rate != 0.0) { - Play(); - StartCurrentTimeUpdateTimer(); - } - - play_rate_ = rate; - - RequestPlayerSeek(GetCurrentTime()); - -#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) - if (!audio_session_manager_->SetSoundState(ASM_STATE_PAUSE)) - return; -#endif -} - -void MediaSourcePlayerGstreamer::RequestPlayerSeek(double seekTime) { - VLOG(1) << "MediaSourcePlayerGstreamer::" << __FUNCTION__ - << " : " << seekTime; - if (is_demuxer_seeking_) - return; - GstState state; - gst_element_get_state(pipeline_, &state, NULL, 250 * GST_NSECOND); - is_demuxer_seeking_ = true; - if (state == GST_STATE_PLAYING) - Pause(true); - manager()->OnRequestSeek(GetPlayerId(), seekTime); -} - -void MediaSourcePlayerGstreamer::Seek(const double time) { - GstState state; - gst_element_get_state(pipeline_, &state, NULL, 250 * GST_NSECOND); - - is_seeking_iframe_ = false; - VLOG(1) << "MediaSourcePlayerGstreamer::" << __FUNCTION__ - << " : " << time << " state : " << gst_element_state_get_name(state); - - is_demuxer_seeking_ = true; - if (state == GST_STATE_PLAYING) - Pause(true); - - // Input to |FromMicroseconds| is |int64|. Additional multiplication - // is done to avoid data loss. - base::TimeDelta seek_time = base::TimeDelta::FromMicroseconds( - static_cast(time * base::Time::kMicrosecondsPerSecond)); - demuxer_->RequestDemuxerSeek(seek_time); -} - -void MediaSourcePlayerGstreamer::SeekInternal(const GstClockTime position) { - if (!pipeline_ || error_occured_) - return; - - GstClockTime startTime, endTime; - - is_demuxer_seeking_ = false; - - if (play_rate_ > 0) { - startTime = position; - endTime = GST_CLOCK_TIME_NONE; - } else { - startTime = 0; - endTime = position; - } - - VLOG(1) << "MediaSourcePlayerGstreamer::" << __FUNCTION__ - << " : " << position; - - UpdateSeekState(true); - audio_buffer_queue_.clear(); - video_buffer_queue_.clear(); - if(!gst_element_seek(pipeline_, play_rate_, GST_FORMAT_TIME, - static_cast(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), - GST_SEEK_TYPE_SET, startTime, GST_SEEK_TYPE_SET, endTime)) { - LOG(ERROR) << "Seek to " << position << " failed"; - HandleError(MediaPlayerTizen::NetworkStateDecodeError); - } -} - -double MediaSourcePlayerGstreamer::GetCurrentTime() { - if (!pipeline_ || error_occured_) - return 0.0; - - gint64 current_time = 0; - GstFormat format = GST_FORMAT_TIME; -#if GST_VERSION_MAJOR == 1 - gst_element_query_position(pipeline_, format, ¤t_time); -#else - gst_element_query_position(pipeline_, &format, ¤t_time); -#endif - return ConvertNanoSecondsToSeconds(current_time); -} - -void MediaSourcePlayerGstreamer::Release() { - VLOG(1) << "MediaSourcePlayerGstreamer::" << __FUNCTION__; - DCHECK(IsPlayerDestructing()); - playing_ = false; - StopCurrentTimeUpdateTimer(); - audio_buffer_queue_.clear(); - video_buffer_queue_.clear(); - - if (pipeline_) { - GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline_)); - if (bus) { - g_signal_handlers_disconnect_by_func( - bus, reinterpret_cast(gst_pipeline_message_cb), this); -#if GST_VERSION_MAJOR == 1 - gst_bus_set_sync_handler(bus, NULL, NULL, NULL); -#else - gst_bus_set_sync_handler(bus, NULL, NULL); -#endif - gst_object_unref(bus); - } - - gst_element_set_state(pipeline_, GST_STATE_NULL); - gst_object_unref(pipeline_); - pipeline_ = NULL; - } - - if (video_sink_pad_) - gst_object_unref(video_sink_pad_); - -#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) - if (!audio_session_manager_->SetSoundState(ASM_STATE_STOP)) - return; - if (!audio_session_manager_->DeallocateResources()) - return; -#endif -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - UnregisterDamageHandler(); - EflPixmapMap::iterator it = efl_pixmaps_map_.begin(); - while (it != efl_pixmaps_map_.end()) { - efl_pixmap_ = it->second; - if (efl_pixmap_.get()) - efl_pixmap_ = NULL; - it++; - } - efl_pixmaps_map_.clear(); -#endif -} - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -void MediaSourcePlayerGstreamer::UnregisterDamageHandler() { - if (m_damage) { - ecore_x_damage_free(m_damage); - m_damage = 0; - } - if (m_damageHandler) { - ecore_event_handler_del(m_damageHandler); - m_damageHandler = 0; - } -} -#endif - -void MediaSourcePlayerGstreamer::SetVolume(double volume) { - if (audio_volume_) - g_object_set(G_OBJECT(audio_volume_), "volume", volume, NULL); -} - -void MediaSourcePlayerGstreamer::OnDemuxerConfigsAvailable( - const DemuxerConfigs& configs) { - if (IsPlayerDestructing()) - return; - - if ((configs.video_codec == kUnknownVideoCodec || - configs.video_codec != kCodecH264) && - (configs.audio_codec == kUnknownAudioCodec || - (configs.audio_codec != kCodecAAC && - configs.audio_codec != kCodecMP3))) { - LOG(ERROR) << "Audio and Video codecs not supported for MediaSource"; - HandleError(MediaPlayerTizen::NetworkStateFormatError); - return; - } - - gst_width_ = configs.video_size.width(); - gst_height_ = configs.video_size.height(); - - if (is_gst_pipeline_constructed_) { - return; - } - is_gst_pipeline_constructed_ = true; - - GError* err = NULL; - if (!gst_is_initialized()) { - gst_init_check(NULL, NULL, &err); - } - - if (gst_is_initialized() && !err) { - pipeline_ = gst_pipeline_new(kPipelineName); - if (!pipeline_) { - LOG(ERROR) << "Unable to Create |Pipeline|"; - HandleError(MediaPlayerTizen::NetworkStateDecodeError); - return; - } - - int i = 0; - while (VideoMapping[i].codec != kUnknownVideoCodec) { - if (configs.video_codec == VideoMapping[i].codec) { - media_type |= MEDIA_VIDEO_MASK; - video_appsrc_ = gst_element_factory_make("appsrc", "video-source"); - video_parse_ = gst_element_factory_make(VideoMapping[i].elements[0], - "video-parse"); - video_queue_ = gst_element_factory_make("queue2", "video-queue"); - video_decoder_ = gst_element_factory_make(VideoMapping[i].elements[1], - "video-decoder"); - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - PrepareForVideoSink(); -#else - PrepareForVideoFrame(); -#endif - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - if (is_backed_by_pixmap) - CreatePixmap(); -#endif - if (!video_appsrc_ || !video_parse_ || !video_queue_ || - !video_decoder_ || !video_sink_) { - LOG(ERROR) << "Not all elements of video pipeline could be created"; - ReleaseVideoElements(); - HandleError(MediaPlayerTizen::NetworkStateDecodeError); - return; - } - - g_object_set(GST_OBJECT(video_appsrc_), "format", GST_FORMAT_TIME, NULL); - g_object_set(GST_OBJECT(video_appsrc_), "stream-type", - GST_APP_STREAM_TYPE_SEEKABLE, NULL); - g_object_set(GST_OBJECT(video_appsrc_), "do-timestamp", false, NULL); - - // Will make the queue to send GST_MESSAGE_BUFFERING - g_object_set(G_OBJECT(video_queue_), "use-buffering", true, NULL); - - // Will trigger need-data callback if buffer goes below 30%, - // default is 10%. Data type of property "low-percent" differs - // on desktop and TIZEN platform. -#if GST_VERSION_MAJOR < 1 - g_object_set(G_OBJECT(video_queue_), "low-percent", (double)30.0, NULL); -#else - g_object_set(G_OBJECT(video_queue_), "low-percent", 30, NULL); -#endif - - gst_bin_add_many(GST_BIN(pipeline_), video_appsrc_, video_queue_, - video_parse_, video_decoder_, video_sink_, NULL); - - // Why |video_queue_| is placed after |video_appsrc_|? - // For understanding puprose consider http://tinyurl.com/qos-iron url. - // For 1080p resolution of the video in above url, each decoded frame - // is of size 2304000 bytes ~ 2.19 MB. If video_queue_ is placed before - // |video_sink_| then queue will buffer decoded frames, so to buffer - // two second worth of data queue will require 2304000*24(fps)*2 ~ 96MB - // of queue size. This property can't be set for pixmap backed playback - // as frame size won't be available for pixmap backed | video_sink|. - // And this size varies from video to video. - // - // But if |video_queue_| is placed after |video_appsrc_|, queue will - // buffer encoded data. For the same video of 1080p, maximum encoded - // frame is of 115398byte ~ 0.110052109 MB. So for 2 sec data, queue - // need to buffer 5308308bytes in queue ~ 5MB, this can be set - // dynamically. Refer |OnDemuxerDataAvailable| for setting queue size. - - gst_element_link_many(video_appsrc_,video_queue_, video_parse_, - video_decoder_, video_sink_, NULL); - static GstAppSrcCallbacks video_callbacks = { - on_gst_start_video_feed_cb, - on_gst_stop_video_feed_cb, - on_gst_seek_video_feed_cb, {NULL}}; - - // FIXME: Try fourth argument for destructy notification. - gst_app_src_set_callbacks(GST_APP_SRC(video_appsrc_), &video_callbacks, - this, NULL); - break; - } - i++; - } - - i = 0; - while (AudioMapping[i].codec != kUnknownAudioCodec) { - if(configs.audio_codec == AudioMapping[i].codec) { - media_type |= MEDIA_AUDIO_MASK; - audio_appsrc_ = gst_element_factory_make("appsrc", "audio-source"); - audio_queue_ = gst_element_factory_make("queue2", "audio-queue"); - audio_parse_ = gst_element_factory_make(AudioMapping[i].elements[0], - "audio-parse"); - audio_decoder_ = gst_element_factory_make(AudioMapping[i].elements[1], - "audio-decoder"); - audio_convert_ = gst_element_factory_make("audioconvert", "audio-convert"); - audio_resampler_ = gst_element_factory_make( - "audioresample", "audio-resample"); - audio_volume_ = gst_element_factory_make("volume", "volume"); - audio_sink_ = gst_element_factory_make( - AudioMapping[i].elements[2], "audio-sink"); - - if (!audio_appsrc_ || !audio_queue_ || !audio_parse_ || - !audio_decoder_ || !audio_convert_ || !audio_resampler_ || - !audio_volume_ || !audio_sink_) { - LOG(ERROR) << "Not all elements of audio pipeline could be created"; - ReleaseAudioElements(); - HandleError(MediaPlayerTizen::NetworkStateDecodeError); - return; - } - - g_object_set( - GST_OBJECT(audio_appsrc_),"format", GST_FORMAT_TIME, NULL); - g_object_set(GST_OBJECT(audio_appsrc_),"stream-type", - GST_APP_STREAM_TYPE_SEEKABLE, NULL); - g_object_set(GST_OBJECT(audio_appsrc_), "do-timestamp", false, NULL); - - g_object_set(G_OBJECT(audio_queue_), "use-buffering", true, NULL); - -#if GST_VERSION_MAJOR < 1 - g_object_set( - G_OBJECT(audio_queue_), "low-percent", (double)30.0, NULL); -#else - g_object_set(G_OBJECT(audio_queue_), "low-percent", 30, NULL); -#endif - - g_object_set(G_OBJECT(audio_volume_), "mute", false, NULL); - -#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) - if (!audio_session_manager_->AllocateResources(audio_decoder_)) - return; - - g_object_set(audio_sink_, "provide-clock", true, "device", "hw:0,0", NULL); - if (!audio_session_manager_->AllocateResources(audio_sink_)) - return; -#endif - - gst_bin_add_many(GST_BIN(pipeline_), audio_appsrc_, audio_queue_, - audio_parse_, audio_decoder_, audio_convert_, audio_resampler_, - audio_volume_, audio_sink_, NULL); - - gst_element_link_many(audio_appsrc_, audio_queue_, audio_parse_, - audio_decoder_, audio_convert_, audio_resampler_, audio_volume_, - audio_sink_, NULL); - - static GstAppSrcCallbacks audio_callbacks = { - on_gst_start_audio_feed_cb, - on_gst_stop_audio_feed_cb, - on_gst_seek_audio_feed_cb, {NULL}}; - - gst_app_src_set_callbacks(GST_APP_SRC(audio_appsrc_), &audio_callbacks, - this, NULL); - break; - } - i++; - } - - GstBus*bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline_)); - if (!bus) { - LOG(ERROR) << "GStreamer bus creation failed"; - HandleError(MediaPlayerTizen::NetworkStateDecodeError); - return; - } -#if GST_VERSION_MAJOR == 1 - gst_bus_set_sync_handler( - bus, (GstBusSyncHandler)gst_pipeline_message_cb, this, NULL); -#else - gst_bus_set_sync_handler( - bus, (GstBusSyncHandler)gst_pipeline_message_cb, this); -#endif - gst_object_unref(bus); - - manager()->OnMediaDataChange(GetPlayerId(), video_format_, - gst_height_, gst_width_, media_type); - - manager()->OnReadyStateChange(GetPlayerId(), - MediaPlayerTizen::ReadyStateHaveMetadata); - - if (gst_element_set_state(pipeline_, GST_STATE_PAUSED) == - GST_STATE_CHANGE_FAILURE) - LOG(ERROR) << "GStreamer state change failed"; - } else { - LOG(ERROR) << "Unable to initialize GST"; - HandleError(MediaPlayerTizen::NetworkStateDecodeError); - } -} - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -void MediaSourcePlayerGstreamer::PrepareForVideoSink() { - video_sink_ = gst_element_factory_make("xvimagesink", "sink"); - if ( video_sink_ == NULL) { - PrepareForVideoFrame(); - } else { - VLOG(1) << "MediaSource using |xvimagesink| for Video Playback"; - is_backed_by_pixmap = true; - video_sink_pad_ = gst_element_get_static_pad(video_sink_, "sink"); - if (video_sink_pad_) { - g_signal_connect(video_sink_pad_, "notify::caps", - G_CALLBACK(on_video_sink_caps_changed_cb), this); - } else { - LOG(ERROR) << " |video_sink_pad_| is NULL ?"; - } - } -} -#endif - -void MediaSourcePlayerGstreamer::PrepareForVideoFrame() { - is_xwindow_handle_set_ = true; - VLOG(1) << "MediaSource using |appsink| for Video Playback"; - video_sink_ = gst_element_factory_make("appsink", "sink"); -#if GST_VERSION_MAJOR == 1 - GstAppSinkCallbacks callbacks = {NULL, on_gst_appsink_preroll, - on_gst_appsink_sample}; -#else - GstAppSinkCallbacks callbacks = {NULL, - on_gst_appsink_preroll, - on_gst_appsink_sample, - NULL, - {NULL, NULL, NULL}}; -#endif - gst_app_sink_set_callbacks(GST_APP_SINK(video_sink_), &callbacks, this, - NULL); - g_object_set(G_OBJECT(video_sink_), "max-buffers", (guint)1, NULL); -} - -void MediaSourcePlayerGstreamer::ReadDemuxedData( - media::DemuxerStream::Type type) { - if (IsPlayerDestructing()) - return; - - if (type == media::DemuxerStream::AUDIO) { - should_feed_audio_ = true; - } else if (type == media::DemuxerStream::VIDEO) { - should_feed_video_ = true; - } else { - LOG(ERROR) << "Unknown Media Type in MediaSourcePlayerGstreamer::" - << __FUNCTION__; - return; - } - demuxer_->RequestDemuxerData(type); -} - -void MediaSourcePlayerGstreamer::OnReadDemuxedData( - media::DemuxerStream::Type type) { - if (IsPlayerDestructing()) { - LOG(ERROR) << __FUNCTION__ << "GST is deinitializing. Just return"; - return; - } - main_loop_->PostTask(FROM_HERE, base::Bind( - &MediaSourcePlayerGstreamer::ReadDemuxedData, base::Unretained(this), - type)); -} - -void MediaSourcePlayerGstreamer::OnStopDemuxedData( - media::DemuxerStream::Type type) { - if (type == media::DemuxerStream::AUDIO) - should_feed_audio_ = false; - else if (type == media::DemuxerStream::VIDEO) - should_feed_video_ = false; - else - LOG(ERROR) << "Unknown Media Type in MediaSourcePlayerGstreamer::" - << __FUNCTION__; -} - -void MediaSourcePlayerGstreamer::OnDemuxerDataAvailable( - base::SharedMemoryHandle foreign_memory_handle, - const media::DemuxedBufferMetaData& meta_data) { - if (!pipeline_ || error_occured_) { - LOG(ERROR) << "Pipeline_ null or error occured"; - return; - } - if (meta_data.size <= 0) { - LOG(ERROR) << "ERROR : Size of shared memory is Zero"; - return; - } - - if (is_seeking_ && !is_seeking_iframe_) { - if (meta_data.type == media::DemuxerStream::VIDEO) { - is_seeking_iframe_ = true; - if (video_seek_offset_ > - (guint64)(meta_data.timestamp.InMicroseconds() * 1000)) { - RequestPlayerSeek((double)(ConvertNanoSecondsToSeconds( - meta_data.timestamp.InMicroseconds() * 1000 - + kSixteenMilliSeconds))); - return; - } - } else if (meta_data.type == media::DemuxerStream::AUDIO) { - if ( audio_seek_offset_ > - (guint64)(meta_data.timestamp.InMicroseconds() * 1000)) - return; - } - } - - ReadFromQueueIfAny(meta_data.type); - if (meta_data.type == media::DemuxerStream::VIDEO) { - if (meta_data.size > raw_video_frame_size_) { - // Dynamically Changing Video Queue Size for Smooth Playback. - // The default queue size limits are 100 buffers, 2MB of data, - // or two seconds worth of data, whichever is reached first. - // Adjust queue to contain two seconds worth of data for smooth playback. - // So need to adjust number of buffers (max-size-buffers >= 2*fps) and - // maximum size of queue (max-size-bytes >= 2*fps*meta_data.size). - // - // 1000000 micro seconds = 1 second. - // 2097152 bytes = 2 MB. - int no_frames_per_two_second , queue_size_for_two_sec; - raw_video_frame_size_ = meta_data.size; - no_frames_per_two_second = 2 * (1000000 / - (meta_data.time_duration.InMicroseconds())); - queue_size_for_two_sec = - raw_video_frame_size_ * no_frames_per_two_second; - if (no_frames_per_two_second > 100) { - g_object_set(G_OBJECT(video_queue_), "max-size-buffers", - no_frames_per_two_second, NULL); - } - if (queue_size_for_two_sec > 2097152) { - g_object_set(G_OBJECT(video_queue_), "max-size-bytes", - queue_size_for_two_sec, NULL); - } - } - } - if (meta_data.type == media::DemuxerStream::AUDIO && !should_feed_audio_) { - // Why store the DecoderBuffer? we have requested for buffer - // from demuxer but gstreamer asked to stop. So need to save - // this buffer and use it on next |need_data| call. - SaveDecoderBuffer(foreign_memory_handle, meta_data); - return; - } - if (meta_data.type == media::DemuxerStream::VIDEO && !should_feed_video_) { - SaveDecoderBuffer(foreign_memory_handle, meta_data); - return; - } - - base::SharedMemory shared_memory(foreign_memory_handle, false); - shared_memory.Map(meta_data.size); - void* ptr; - gint size = meta_data.size; - GstFlowReturn ret = GST_FLOW_OK; - ptr = g_malloc(size); - memcpy(ptr, shared_memory.memory(), size); - -#if GST_VERSION_MAJOR == 1 - GstBuffer* buffer = gst_buffer_new_allocate(NULL, meta_data.size, NULL); - gst_buffer_fill (buffer, 0, ptr, meta_data.size); -#else - GstBuffer* buffer = gst_buffer_new(); - GST_BUFFER_MALLOCDATA(buffer) = (uint8*)ptr; - GST_BUFFER_SIZE(buffer) = size; - GST_BUFFER_DATA(buffer) = GST_BUFFER_MALLOCDATA(buffer); -#endif - GST_BUFFER_TIMESTAMP (buffer) = - (guint64)(meta_data.timestamp.InMicroseconds() * 1000); - GST_BUFFER_DURATION (buffer) = - (guint64)(meta_data.time_duration.InMicroseconds() * 1000); - - if (meta_data.type == media::DemuxerStream::AUDIO) - ret = gst_app_src_push_buffer(GST_APP_SRC(audio_appsrc_), buffer); - else if (meta_data.type == media::DemuxerStream::VIDEO) - ret = gst_app_src_push_buffer(GST_APP_SRC(video_appsrc_), buffer); - - // gst_app_src_push_buffer() takes ownership of the buffer. - // Hence no need to unref buffer. - if (ret != GST_FLOW_OK) { - LOG(ERROR) << __FUNCTION__ << " : Gstreamer appsrc push failed : " << ret; - shared_memory.Close(); - return; - } - - if (meta_data.type == media::DemuxerStream::AUDIO && should_feed_audio_) - OnReadDemuxedData(media::DemuxerStream::AUDIO); - else if (meta_data.type == media::DemuxerStream::VIDEO && should_feed_video_) - OnReadDemuxedData(media::DemuxerStream::VIDEO); - shared_memory.Close(); - return; -} - -void MediaSourcePlayerGstreamer::OnBufferMetaDataAvailable( - const media::DemuxedBufferMetaData& meta_data) { - - if (!pipeline_ || error_occured_) { - LOG(ERROR) << "Pipeline_ null or error occured"; - return; - } - - switch (meta_data.status) { - case media::DemuxerStream::kAborted: - // FIXME : Need to handle Aborted state Properly. - if (meta_data.type == media::DemuxerStream::AUDIO && should_feed_audio_) - OnReadDemuxedData(media::DemuxerStream::AUDIO); - else if (meta_data.type == media::DemuxerStream::VIDEO && - should_feed_video_) - OnReadDemuxedData(media::DemuxerStream::VIDEO); - break; - - case media::DemuxerStream::kConfigChanged: - if (meta_data.type == media::DemuxerStream::AUDIO && should_feed_audio_) - OnReadDemuxedData(media::DemuxerStream::AUDIO); - else if (meta_data.type == media::DemuxerStream::VIDEO && - should_feed_video_) - OnReadDemuxedData(media::DemuxerStream::VIDEO); - - if (meta_data.type == media::DemuxerStream::AUDIO) - VLOG(1) << "[BROWSER] : AUDIO::kConfigChanged"; - if (meta_data.type == media::DemuxerStream::VIDEO) - VLOG(1) << "[BROWSER] : VIDEO::kConfigChanged"; - break; - - case media::DemuxerStream::kOk: - if (meta_data.end_of_stream) { - ReadFromQueueIfAny(meta_data.type); - LOG(ERROR) <<"[BROWSER] : DemuxerStream::kOk but |end_of_stream|"; - if (meta_data.type == media::DemuxerStream::AUDIO) - gst_app_src_end_of_stream(GST_APP_SRC(audio_appsrc_)); - if (meta_data.type == media::DemuxerStream::VIDEO) - gst_app_src_end_of_stream(GST_APP_SRC(video_appsrc_)); - if (playing_) - Play(); - } - break; - - default: - NOTREACHED(); - } -} - -void MediaSourcePlayerGstreamer::ReadFromQueueIfAny( - DemuxerStream::Type type) { - if (!pipeline_ || error_occured_) { - LOG(ERROR) << "Pipeline_ null or error occured"; - return; - } - - if (type == media::DemuxerStream::AUDIO) { - if (audio_buffer_queue_.empty() || !should_feed_audio_) - return; - } - - if (type == media::DemuxerStream::VIDEO) { - if (video_buffer_queue_.empty() || !should_feed_video_) - return; - } - - scoped_refptr decoder_buffer; - if (type == media::DemuxerStream::AUDIO) { - decoder_buffer = audio_buffer_queue_.front(); - audio_buffer_queue_.pop_front(); - } else { - decoder_buffer = video_buffer_queue_.front(); - video_buffer_queue_.pop_front(); - } - - void* ptr; - GstFlowReturn ret; - gint size = decoder_buffer.get()->data_size(); - ptr = g_malloc(size); - memcpy(ptr, (void*)decoder_buffer.get()->writable_data(), size); -#if GST_VERSION_MAJOR == 1 - GstBuffer* buffer = gst_buffer_new_allocate(NULL, size, NULL); - gst_buffer_fill (buffer, 0, ptr, size); -#else - GstBuffer* buffer = gst_buffer_new(); - GST_BUFFER_MALLOCDATA(buffer) = (uint8*)ptr; - GST_BUFFER_SIZE(buffer) = size; - GST_BUFFER_DATA(buffer) = GST_BUFFER_MALLOCDATA(buffer); -#endif - GST_BUFFER_TIMESTAMP (buffer) = - (guint64)(decoder_buffer.get()->timestamp().InMicroseconds() * 1000); - GST_BUFFER_DURATION (buffer) = - (guint64)(decoder_buffer.get()->duration().InMicroseconds() * 1000); - - if (type == media::DemuxerStream::AUDIO) - ret = gst_app_src_push_buffer(GST_APP_SRC(audio_appsrc_), buffer); - else - ret = gst_app_src_push_buffer(GST_APP_SRC(video_appsrc_), buffer); - if (ret != GST_FLOW_OK) - return; - - //Empty the Buffer before reading the new buffer from render process. - ReadFromQueueIfAny(type); - return; -} - -void MediaSourcePlayerGstreamer::SaveDecoderBuffer( - base::SharedMemoryHandle foreign_memory_handle, - const media::DemuxedBufferMetaData& meta_data) { - if (!pipeline_ || error_occured_) { - LOG(ERROR) << "Pipeline_ null or error occured"; - return; - } - - base::SharedMemory shared_memory(foreign_memory_handle, false); - shared_memory.Map(meta_data.size); - scoped_refptr buffer; - buffer = DecoderBuffer::CopyFrom(static_cast ( - shared_memory.memory()), meta_data.size); - - if (!buffer.get()) { - LOG(ERROR) << "DecoderBuffer::CopyFrom failed"; - shared_memory.Close(); - return; - } - - buffer->set_timestamp(meta_data.timestamp); - buffer->set_duration(meta_data.time_duration); - - if (meta_data.type == media::DemuxerStream::AUDIO) - audio_buffer_queue_.push_back(buffer); - else - video_buffer_queue_.push_back(buffer); - - shared_memory.Close(); -} - -void MediaSourcePlayerGstreamer::GetFrameDetails() { - if (!pipeline_ || error_occured_) - return; - - GstState state; - GstState pending; - GstStateChangeReturn ret = gst_element_get_state(pipeline_, - &state, &pending, 250 * GST_NSECOND); - VLOG(1) << "MediaSourcePlayerGstreamer::" - << __FUNCTION__ - << " GstStateChangeReturn: " - << gst_element_state_change_return_get_name(ret) - << " state: " - << gst_element_state_get_name(state) - << " pending: " - << gst_element_state_get_name(pending) - << " ID " << GetPlayerId(); - - // Get details only after prerolling. - if (pending >= GST_STATE_PAUSED) - main_loop_->PostTask(FROM_HERE, base::Bind( - &MediaSourcePlayerGstreamer::OnGetFrameDetails, - base::Unretained(this))); -} - -void MediaSourcePlayerGstreamer::OnGetFrameDetails() { - if (!pipeline_ || IsPlayerDestructing() || error_occured_) - return; -#if GST_VERSION_MAJOR == 1 - GstSample* sample = gst_app_sink_pull_preroll(GST_APP_SINK(video_sink_)); - if (!sample) - return; - - GstCaps* caps = gst_sample_get_caps(sample); - if (!caps) - return; - - GstVideoInfo vi; - gst_video_info_from_caps(&vi, caps); - - gst_width_ = GST_VIDEO_INFO_WIDTH(&vi); - gst_height_ = GST_VIDEO_INFO_HEIGHT(&vi); - switch(GST_VIDEO_INFO_FORMAT(&vi)) { - case GST_VIDEO_FORMAT_I420:{ - video_format_ = GST_MAKE_FOURCC('I','4','2','0'); - break; - } - case GST_VIDEO_FORMAT_NV12:{ - video_format_ = GST_MAKE_FOURCC('N','V','1','2'); - break; - } - default: - LOG(ERROR) << "Unknown format : " << GST_VIDEO_INFO_FORMAT(&vi); - break; - } -#else - - GstBuffer* sample = gst_app_sink_pull_preroll(GST_APP_SINK(video_sink_)); - - if (!sample) - return; - GstCaps* caps = gst_buffer_get_caps(GST_BUFFER(sample)); - if (!caps) { - gst_buffer_unref(sample); - return; - } - - // No need to unref |GstStructure| - const GstStructure* str = gst_caps_get_structure(caps, 0); - gst_caps_unref(caps); - gst_buffer_unref(sample); - if (!str) - return; - - if (!gst_structure_get_int(str, "width", &gst_width_) || - !gst_structure_get_int(str, "height", &gst_height_) || - !gst_structure_get_fourcc(str, "format", &video_format_)) { - LOG(ERROR) << "Pre-rolled sample information could not be obtained"; - } -#endif - - if(video_format_ == GST_VIDEO_SN12) { - uint tile_w_align = ((gst_width_ - 1) / SN12_TILE_WIDTH + 2) & ~1; - bufsize_sn12_ = - SN12_TILE_SIZE * tile_w_align * ((gst_height_-1)/SN12_TILE_HEIGHT+1) - + (((gst_height_+1)&~1)/2) * tile_w_align * SN12_TILE_WIDTH; - } - manager()->OnMediaDataChange(GetPlayerId(), video_format_, - gst_height_, gst_width_, media_type); -} - -#if GST_VERSION_MAJOR == 1 -GstSample* MediaSourcePlayerGstreamer::PullSample() { - return gst_app_sink_pull_sample(GST_APP_SINK(video_sink_)); -} - -void MediaSourcePlayerGstreamer::OnNewFrameAvailable(GstSample* sample) { - if (!pipeline_ || error_occured_) - return; - - GstMapInfo map; - GstBuffer* buffer = gst_sample_get_buffer(sample); - if (!gst_buffer_map(buffer, &map, GST_MAP_READ)) { - LOG (ERROR) << "Sample contains invalid or no info!"; - return; - } - - if (!gst_width_ || !gst_height_) - GetFrameDetails(); - - GstCaps* caps = gst_sample_get_caps(sample); - if (caps) { - GstVideoInfo vi; - gst_video_info_from_caps(&vi, caps); - int width = GST_VIDEO_INFO_WIDTH(&vi); - int height = GST_VIDEO_INFO_HEIGHT(&vi); - - if (width != gst_width_|| height != gst_height_) { - LOG (INFO) << __FUNCTION__ - << " ###### from " << gst_width_ << "X" << gst_height_ - << " to " << width << "X" << height; - gst_width_ = width; - gst_height_ = height; - manager()->OnMediaDataChange( - GetPlayerId(), video_format_, gst_height_, gst_width_, media_type); - } - } - - base::TimeDelta timestamp = - base::TimeDelta::FromMicroseconds( - GST_BUFFER_TIMESTAMP(buffer) / - base::Time::kNanosecondsPerMicrosecond); - - if(video_format_ == GST_VIDEO_SN12) - shared_memory_size = (bufsize_sn12_); - else - shared_memory_size = (map.size); - - if (!shared_memory.CreateAndMapAnonymous(shared_memory_size)) { - LOG (ERROR) << "Shared Memory creation failed."; - gst_buffer_unmap(buffer, &map); - gst_sample_unref(sample); - return; - } - - if (!shared_memory.ShareToProcess(base::Process::Current().Handle(), - &foreign_memory_handle)) { - LOG (ERROR) << "Shared Memory handle could not be obtained"; - shared_memory.Close(); - gst_buffer_unmap(buffer, &map); - gst_sample_unref(sample); - return; - } - - memcpy(shared_memory.memory(), map.data, shared_memory_size); - manager()->OnNewFrameAvailable( - GetPlayerId(), foreign_memory_handle, shared_memory_size, timestamp); - - shared_memory.Close(); - gst_buffer_unmap(buffer, &map); - gst_sample_unref(sample); -} -#else -GstBuffer* MediaSourcePlayerGstreamer::PullSample() { - return gst_app_sink_pull_buffer(GST_APP_SINK(video_sink_)); -} - -void MediaSourcePlayerGstreamer::OnNewFrameAvailable(const GstBuffer* buffer) { - if (!pipeline_ || error_occured_) - return; - if (!buffer) - return; - if (!GST_BUFFER_DATA(buffer) || !GST_BUFFER_SIZE(buffer)) - return; - - if (!gst_width_ || !gst_height_) - GetFrameDetails(); - // FIXME: Cross check the end results. - base::TimeDelta timestamp = - base::TimeDelta::FromMicroseconds( - GST_BUFFER_TIMESTAMP(buffer) / - base::Time::kNanosecondsPerMicrosecond); - - uint8* buffer_data = GST_BUFFER_DATA(buffer); - gsize buffer_size = GST_BUFFER_SIZE(buffer); - - if(video_format_ == GST_VIDEO_SN12) - shared_memory_size = (bufsize_sn12_); - else - shared_memory_size = (buffer_size); - - if (!shared_memory.CreateAndMapAnonymous(shared_memory_size)) { - LOG (ERROR) << "Shared Memory creation failed."; - gst_buffer_unref(GST_BUFFER(buffer)); - return; - } - - if (!shared_memory.ShareToProcess(base::Process::Current().Handle(), - &foreign_memory_handle)) { - LOG (ERROR) << "Shared Memory handle could not be obtained"; - shared_memory.Close(); - gst_buffer_unref(GST_BUFFER(buffer)); - return; - } - - memcpy(shared_memory.memory(), buffer_data, shared_memory_size); - manager()->OnNewFrameAvailable( - GetPlayerId(), foreign_memory_handle, shared_memory_size, timestamp); - - shared_memory.Close(); - gst_buffer_unref(GST_BUFFER(buffer)); -} -#endif - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -void MediaSourcePlayerGstreamer::XWindowIdPrepared(GstMessage* message) { - gint width, height; -#if GST_VERSION_MAJOR == 1 - const GstStructure* structure = gst_message_get_structure(message); - - gst_structure_get_int(structure, "video-width", &width); - gst_structure_get_int(structure, "video-height", &height); -#else - gst_structure_get_int(message->structure, "video-width", &width); - gst_structure_get_int(message->structure, "video-height", &height); -#endif - if ((gst_width_ != width) || (gst_height_ != height)) { - LOG(ERROR) << "Demuxer Video Configs and Gstreamer Video Configs doesn't" - <<" match.From Demuxer : width : "<OnMediaDataChange( - GetPlayerId(), video_format_, gst_height_, gst_width_, media_type); -} - -void MediaSourcePlayerGstreamer::PlatformSurfaceUpdated() { - gint64 current_time = 0; - GstFormat format = GST_FORMAT_TIME; -#if GST_VERSION_MAJOR == 1 - gst_element_query_position(pipeline_, format, ¤t_time); -#else - gst_element_query_position(pipeline_, &format, ¤t_time); -#endif - base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds( - current_time / base::Time::kNanosecondsPerMicrosecond); - manager()->OnPlatformSurfaceUpdated(GetPlayerId(), pixmap_id_, timestamp); -} - -int MediaSourcePlayerGstreamer::GetSurfaceID() const { - return pixmap_id_; -} - -void MediaSourcePlayerGstreamer::SetPixmap() { -#if GST_VERSION_MAJOR == 1 - gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(video_sink_), pixmap_id_); -#else -#if defined(OS_TIZEN_TV) - // Using below statements on mobile to set pixmap was causing two issue. - // 1. Video size was different than the required one whenever configaration - // changed - // 2. Sometime black screen was appearing, while video was playing. - // Hence for mobile keeping implementation which uses - // |gst_x_overlay_set_window_handle|to sep Pixmap. - g_object_set (video_sink_, "pixmap-id-callback", get_pixmap_id_cb, NULL); - g_object_set (video_sink_, "pixmap-id-callback-userdata", this, NULL); -#else - gst_x_overlay_set_window_handle(GST_X_OVERLAY(video_sink_), pixmap_id_); -#endif -#endif - m_damage = ecore_x_damage_new(pixmap_id_, - ECORE_X_DAMAGE_REPORT_RAW_RECTANGLES); - m_damageHandler = ecore_event_handler_add(ECORE_X_EVENT_DAMAGE_NOTIFY, - notify_damage_updated_cb, this); - g_object_set(video_sink_, "rotate", 0, NULL); - is_xwindow_handle_set_ = true; -} - -void MediaSourcePlayerGstreamer::OnVideoConfigsChanged() { - if (!pipeline_ || error_occured_) - return; - main_loop_->PostTask(FROM_HERE, base::Bind( - &MediaSourcePlayerGstreamer::VideoConfigsChanged, - base::Unretained(this))); -} - -void MediaSourcePlayerGstreamer::VideoConfigsChanged() { - if (!pipeline_ || IsPlayerDestructing() || error_occured_) - return; - VLOG(1) << "Video Configs Changed, so changing the pixmap"; - gint width, height; - -#if GST_VERSION_MAJOR == 1 - GstCaps* caps = gst_pad_get_current_caps(GST_PAD(video_sink_pad_)); - if (caps) { - GstVideoInfo info; - gst_video_info_init(&info); - - if (gst_video_info_from_caps(&info, caps)) { - width = info.width; - height = info.height; - } - } -#else - if (gst_video_get_size(video_sink_pad_, &width, &height)) { - LOG(ERROR) << "Cannot get width / height!"; - return; - } -#endif - if ((gst_width_ != width) || (gst_height_ != height)) { - LOG(ERROR) << "Demuxer Video Configs and Gstreamer Video Configs doesn't" - <<" match.From Demuxer : width : "<OnMediaDataChange( - GetPlayerId(), video_format_, gst_height_, gst_width_, media_type); - } -} - -void MediaSourcePlayerGstreamer::CreatePixmap() { - bool is_create_new = false; - std::string string_wh = - ConvertWidthAndHeightToString(gst_width_, gst_height_); - if (efl_pixmaps_map_.size() == 0) - is_create_new = true; - - if (!is_create_new) { - EflPixmapMap::iterator it = efl_pixmaps_map_.find(string_wh); - if (it != efl_pixmaps_map_.end()) { - is_create_new = false; - efl_pixmap_ = it->second; - pixmap_id_ = efl_pixmap_->GetId(); - } else { - is_create_new = true; - } - } - - if (is_create_new) { - efl_pixmap_ = gfx::EflPixmap::Create(gfx::EflPixmap::SURFACE, - gfx::Size(gst_width_, gst_height_)); - if (!efl_pixmap_.get()) { - LOG(ERROR) << "gfx::EflPixmap::Create() failed to create Pixmap"; - return; - } - pixmap_id_ = efl_pixmap_->GetId(); - efl_pixmaps_map_[string_wh] = efl_pixmap_; - } -} -#endif - -void MediaSourcePlayerGstreamer::OnDemuxerDurationChanged( - base::TimeDelta duration) { - duration_ = duration.InSecondsF(); -} - -void MediaSourcePlayerGstreamer::OnDemuxerSeekDone( - const base::TimeDelta& actual_browser_seek_time) { - VLOG(1) << "MediaSourcePlayerGstreamer::" << __FUNCTION__ << " : " - << actual_browser_seek_time.InSecondsF(); - SeekInternal(ConvertToGstClockTime(actual_browser_seek_time.InSecondsF())); -} - -bool MediaSourcePlayerGstreamer::HasVideo() { - return media_type & MEDIA_VIDEO_MASK; -} - -bool MediaSourcePlayerGstreamer::HasAudio() { - return media_type & MEDIA_AUDIO_MASK; -} - -void MediaSourcePlayerGstreamer::OnCurrentTimeUpdateTimerFired() { - manager()->OnTimeUpdate(GetPlayerId(), GetCurrentTime()); -} - -void MediaSourcePlayerGstreamer::StartCurrentTimeUpdateTimer() { - if (!current_time_update_timer_.IsRunning()) { - current_time_update_timer_.Start( - FROM_HERE, - base::TimeDelta::FromMilliseconds(kDurationUpdateInterval), - this, &MediaSourcePlayerGstreamer::OnCurrentTimeUpdateTimerFired); - } -} - -void MediaSourcePlayerGstreamer::StopCurrentTimeUpdateTimer() { - if (current_time_update_timer_.IsRunning()) - current_time_update_timer_.Stop(); -} - -void MediaSourcePlayerGstreamer::HandleMessage(GstMessage* message) { - if (!pipeline_ || error_occured_) - return; - if (!strcmp(kPipelineName, GST_MESSAGE_SRC_NAME(message))) - VLOG(1) << "MediaSourcePlayerGstreamer::" << __FUNCTION__ - << " Message " << GST_MESSAGE_TYPE_NAME(message) - << " received from element " << GST_MESSAGE_SRC_NAME(message) - << " ID " << GetPlayerId(); - - switch (GST_MESSAGE_TYPE(message)) { - case GST_MESSAGE_ELEMENT: -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - if (!IsXWindowHadleSet() && -#if GST_VERSION_MAJOR == 1 - gst_is_video_overlay_prepare_window_handle_message(message)) { -#else - message->structure && - gst_structure_has_name(message->structure, "prepare-xid")) { -#endif - LOG(INFO) << "Received message : Video overlay prepared"; - XWindowIdPrepared(message); - return; - } -#endif - case GST_MESSAGE_ERROR: - GError* error; - gst_message_parse_error(message, &error, NULL); - MediaPlayerTizen::NetworkState network_state_error; - network_state_error = MediaPlayerTizen::NetworkStateEmpty; - if (error->code == GST_STREAM_ERROR_CODEC_NOT_FOUND - || error->code == GST_STREAM_ERROR_WRONG_TYPE - || error->code == GST_STREAM_ERROR_FAILED - || error->code == GST_RESOURCE_ERROR_NOT_FOUND) { - network_state_error = MediaPlayerTizen::NetworkStateFormatError; - } else if (error->domain == GST_RESOURCE_ERROR) { - network_state_error = MediaPlayerTizen::NetworkStateNetworkError; - } else { - network_state_error = MediaPlayerTizen::NetworkStateDecodeError; - } -#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) - if (!audio_session_manager_->SetSoundState(ASM_STATE_STOP)) - return; - if (!audio_session_manager_->DeallocateResources()) - return; -#endif - LOG(ERROR) << "Error Message : " << error->message << " Recieved From : " - << GST_MESSAGE_SRC_NAME(message) - << ", and Blink Error Code = " << network_state_error; - g_error_free(error); - HandleError(network_state_error); - break; - case GST_MESSAGE_EOS: - VLOG(1) << "GST_MESSAGE_EOS"; -#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) - if (!audio_session_manager_->SetSoundState(ASM_STATE_STOP)) - return; - if (!audio_session_manager_->DeallocateResources()) - return; -#endif - main_loop_->PostTask(FROM_HERE, base::Bind( - &MediaSourcePlayerGstreamer::OnPlaybackComplete, - base::Unretained(this))); - break; - case GST_MESSAGE_ASYNC_DONE: - VLOG(1) << "HandleMessage : GST_MESSAGE_ASYNC_DONE : is_seeking_ = " - << is_seeking_; - if (is_seeking_) { - is_seeking_iframe_ = false; - main_loop_->PostTask(FROM_HERE, base::Bind( - &MediaSourcePlayerGstreamer::UpdateSeekState, - base::Unretained(this), false)); - - // Initiate play for internal seeks. - if (playing_) - main_loop_->PostTask(FROM_HERE, base::Bind( - &MediaSourcePlayerGstreamer::Play, base::Unretained(this))); - - manager()->OnTimeUpdate(GetPlayerId(), GetCurrentTime()); - main_loop_->PostTask(FROM_HERE, base::Bind( - &MediaSourcePlayerGstreamer::OnTimeChanged, base::Unretained(this))); - } - - // FIXME: Do we need to pull caps from PARSER? Can ignore if its of no use. - break; - case GST_MESSAGE_STATE_CHANGED: - if (strcmp(kPipelineName, GST_MESSAGE_SRC_NAME(message))) - break; - main_loop_->PostTask(FROM_HERE, base::Bind( - &MediaSourcePlayerGstreamer::OnUpdateStates, base::Unretained(this))); - break; - case GST_MESSAGE_BUFFERING: - int buffered; - gst_message_parse_buffering(message, &buffered); - - if (audio_queue_ && GST_MESSAGE_SRC(message) == GST_OBJECT(audio_queue_)) - audio_buffered_ = buffered; - if (video_queue_ && GST_MESSAGE_SRC(message) == GST_OBJECT(video_queue_)) - video_buffered_ = buffered; - - if (!is_paused_due_underflow_ && playing_) { - if (audio_buffered_ < 100 || video_buffered_ < 100) { - main_loop_->PostTask(FROM_HERE, base::Bind( - &MediaSourcePlayerGstreamer::HandleBufferingMessage, - base::Unretained(this))); - } - } else if (is_paused_due_underflow_ && playing_) { - if ((!HasAudio() || audio_buffered_ == 100) && - (!HasVideo() || video_buffered_ == 100)) { - main_loop_->PostTask(FROM_HERE, base::Bind( - &MediaSourcePlayerGstreamer::HandleBufferingMessage, - base::Unretained(this))); - } - } - break; - default: - VLOG(1) << "Unhandled GStreamer message type: " - << GST_MESSAGE_TYPE_NAME(message); - break; - } -} - -void MediaSourcePlayerGstreamer::OnUpdateStates() { - DCHECK(main_loop_->BelongsToCurrentThread()); - if (!pipeline_ || IsPlayerDestructing() || error_occured_) - return; - - GstState state; - GstState pending; - GstStateChangeReturn ret = gst_element_get_state( - pipeline_, &state, &pending, 250 * GST_NSECOND); - - VLOG(1) << "MediaSourcePlayerGstreamer::" - << __FUNCTION__ - << " GstStateChangeReturn: " - << gst_element_state_change_return_get_name(ret) - << " state: " - << gst_element_state_get_name(state) - << " pending: " - << gst_element_state_get_name(pending) - << " ID " << GetPlayerId(); - - // FIXME: Handle all state changes - switch (ret) { - case GST_STATE_CHANGE_SUCCESS: - switch (state) { - case GST_STATE_PAUSED: - manager()->OnReadyStateChange( - GetPlayerId(), MediaPlayerTizen::ReadyStateHaveEnoughData); - break; - default: - VLOG(1) << "GStreamer unhandled state " - << gst_element_state_get_name(state); - break; - } - break; - case GST_STATE_CHANGE_FAILURE: - LOG(ERROR) << "Failure: State: " - << gst_element_state_get_name(state) - << " pending: " - << gst_element_state_get_name(pending); - HandleError(MediaPlayerTizen::NetworkStateDecodeError); - break; - case GST_STATE_CHANGE_NO_PREROLL: - - break; - default: - VLOG(1) << "Unhandled return type: " << ret; - break; - } -} - -void MediaSourcePlayerGstreamer::HandleBufferingMessage() { - if (IsPlayerDestructing()) - return; - if (!is_paused_due_underflow_ && - (audio_buffered_ < 100 || video_buffered_ < 100)) { - is_paused_due_underflow_ = true; - Pause(true); - manager()->OnReadyStateChange(GetPlayerId(), - MediaPlayerTizen::ReadyStateHaveCurrentData); - manager()->OnNetworkStateChange(GetPlayerId(), - MediaPlayerTizen::NetworkStateLoading); - } else if (is_paused_due_underflow_ && - (!HasAudio() || audio_buffered_ == 100) && - (!HasVideo() || video_buffered_ == 100)) { - is_paused_due_underflow_ = false; - Play(); - manager()->OnReadyStateChange(GetPlayerId(), - MediaPlayerTizen::ReadyStateHaveEnoughData); - manager()->OnNetworkStateChange(GetPlayerId(), - MediaPlayerTizen::NetworkStateLoaded); - } -} - -void MediaSourcePlayerGstreamer::OnPlaybackComplete() { - // GStreamer pipeline EOS time and media duration doesnt match. - double time = GetCurrentTime() != duration_ ? duration_ : GetCurrentTime(); - is_end_reached_ = true; - is_download_finished_ = false; - StopCurrentTimeUpdateTimer(); - manager()->OnTimeUpdate(GetPlayerId(), time); - manager()->OnTimeChanged(GetPlayerId()); - -#if defined(OS_TIZEN_MOBILE) && (defined(TIZEN_V_2_3) || defined(TIZEN_V_2_4)) - if (device_power_release_lock(POWER_LOCK_DISPLAY) != DEVICE_ERROR_NONE) - LOG(ERROR) << "|device_power_release_lock| request failed"; -#endif - -} - -void MediaSourcePlayerGstreamer::UpdateSeekState(bool state) { - manager()->OnSeekStateChange(GetPlayerId(), state); - is_seeking_ = state; -} - -void MediaSourcePlayerGstreamer::OnTimeChanged() { - VLOG(1) << "OnTimeChanged" << "Player ID : " << GetPlayerId(); - DCHECK(main_loop_->BelongsToCurrentThread()); - manager()->OnTimeChanged(GetPlayerId()); -} - -void MediaSourcePlayerGstreamer::HandleError( - media::MediaPlayerTizen::NetworkState state) { - error_occured_ = true; - manager()->OnNetworkStateChange(GetPlayerId(), state); - -#if defined(OS_TIZEN_MOBILE) && (defined(TIZEN_V_2_3) || defined(TIZEN_V_2_4)) - if (device_power_release_lock(POWER_LOCK_DISPLAY) != DEVICE_ERROR_NONE) - LOG(ERROR) << "|device_power_release_lock| request failed"; -#endif - -} - -void MediaSourcePlayerGstreamer::ReleaseAudioElements() { - if (audio_appsrc_) { - gst_object_unref(audio_appsrc_); - audio_appsrc_ = NULL; - } - - if (audio_queue_) { - gst_object_unref(audio_queue_); - audio_queue_ = NULL; - } - - if (audio_parse_) { - gst_object_unref(audio_parse_); - audio_parse_ = NULL; - } - - if (audio_decoder_) { - gst_object_unref(audio_decoder_); - audio_decoder_ = NULL; - } - - if (audio_convert_) { - gst_object_unref(audio_convert_); - audio_convert_ = NULL; - } - - if (audio_resampler_) { - gst_object_unref(audio_resampler_); - audio_resampler_ = NULL; - } - - if (audio_volume_) { - gst_object_unref(audio_volume_); - audio_volume_ = NULL; - } - - if (audio_sink_) { - gst_object_unref(audio_sink_); - audio_sink_ = NULL; - } -} - -void MediaSourcePlayerGstreamer::ReleaseVideoElements() { - if(video_appsrc_) { - gst_object_unref(video_appsrc_); - video_appsrc_ = NULL; - } - - if(video_parse_) { - gst_object_unref(video_parse_); - video_parse_ = NULL; - } - - if(video_queue_) { - gst_object_unref(video_queue_); - video_queue_ = NULL; - } - - if(video_decoder_) { - gst_object_unref(video_decoder_); - video_decoder_ = NULL; - } - - if(video_sink_) { - gst_object_unref(video_sink_); - video_sink_ = NULL; - } -} - -} // namespace media diff --git a/tizen_src/impl/media/base/tizen/media_source_player_gstreamer.h b/tizen_src/impl/media/base/tizen/media_source_player_gstreamer.h deleted file mode 100644 index f507e170c2fd..000000000000 --- a/tizen_src/impl/media/base/tizen/media_source_player_gstreamer.h +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MEDIA_BASE_TIZEN_MEDIA_SOURCE_PLAYER_GSTREAMER_H_ -#define MEDIA_BASE_TIZEN_MEDIA_SOURCE_PLAYER_GSTREAMER_H_ - -#include - -#include -#include "ecore_x_wrapper.h" -#include - -#include "base/cancelable_callback.h" -#include "base/memory/scoped_ptr.h" -#include "base/threading/thread.h" -#include "base/time/default_tick_clock.h" -#include "base/timer/timer.h" -#include "media/base/tizen/demuxer_tizen.h" -#include "media/base/tizen/media_player_tizen.h" -#include "media/base/decoder_buffer.h" - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -#include "ui/gl/efl_pixmap.h" -#endif - -#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) -#include "media/audio/tizen/audio_session_manager.h" -#endif - -namespace { -struct AudioCodecGstElementsMapping { - media::AudioCodec codec; - const char **elements; -}; - -struct VideoCodecGstElementsMapping { - media::VideoCodec codec; - const char **elements; -}; -} - -namespace media { - -// This class handles media source extensions for Gstreamer port. -class MEDIA_EXPORT MediaSourcePlayerGstreamer : public MediaPlayerTizen, - public DemuxerTizenClient { - public: - - // Constructs a player with the given ID and demuxer. |manager| must outlive - // the lifetime of this object. - MediaSourcePlayerGstreamer( - int player_id, - scoped_ptr demuxer, - MediaPlayerManager* manager); - - virtual ~MediaSourcePlayerGstreamer(); - - // MediaPlayerTizen implementation. - virtual void Play() override; - virtual void Pause(bool is_media_related_action) override; - virtual void SetRate(double rate) override; - virtual void Seek(const double time) override; - virtual void SetVolume(double volume) override; - virtual double GetCurrentTime() override; - virtual void Destroy() override; - - // DemuxerTizenClient implementation. - virtual void OnDemuxerConfigsAvailable( - const DemuxerConfigs& params) override; - virtual void OnDemuxerDataAvailable( - base::SharedMemoryHandle foreign_memory_handle, - const media::DemuxedBufferMetaData& meta_data) override; - virtual void OnBufferMetaDataAvailable( - const media::DemuxedBufferMetaData& meta_data) override; - virtual void OnDemuxerSeekDone( - const base::TimeDelta& actual_browser_seek_time) override; - virtual void OnDemuxerDurationChanged(base::TimeDelta duration) override; - - // GStreamer Message handler - void HandleMessage(GstMessage* message); - - // AppSink related - void GetFrameDetails(); -#if GST_VERSION_MAJOR == 1 - GstSample* PullSample(); - void OnNewFrameAvailable(GstSample* sample); -#else - GstBuffer* PullSample(); - void OnNewFrameAvailable(const GstBuffer* buffer); -#endif - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - void PlatformSurfaceUpdated(); - void OnVideoConfigsChanged(); - int GetSurfaceID() const; -#endif - - void OnReadDemuxedData(media::DemuxerStream::Type type); - void OnStopDemuxedData(media::DemuxerStream::Type type); - - void UpdateVideoSeekOffset(guint64 video_seek_offset) { - video_seek_offset_ = video_seek_offset; - } - void UpdateAudioSeekOffset(guint64 audio_seek_offset) { - audio_seek_offset_ = audio_seek_offset; - } - - protected: - virtual void Release() override; - - private: - void PrepareForVideoFrame(); - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - void PrepareForVideoSink(); - void VideoConfigsChanged(); - void CreatePixmap(); - void SetPixmap(); - bool IsXWindowHadleSet() { return is_xwindow_handle_set_;} - void XWindowIdPrepared(GstMessage*); - void UnregisterDamageHandler(); -#endif - - void ReadDemuxedData(media::DemuxerStream::Type type); - void SaveDecoderBuffer( - base::SharedMemoryHandle foreign_memory_handle, - const media::DemuxedBufferMetaData& meta_data); - void ReadFromQueueIfAny(DemuxerStream::Type type); - - bool HasAudio(); - bool HasVideo(); - - // Note: Must be invoked only if elements are not added into the pipeline. - void ReleaseAudioElements(); - void ReleaseVideoElements(); - - void SeekInternal(const GstClockTime time); - - // For internal seeks. - void RequestPlayerSeek(double seekTime); - - // |current_time_update_timer_| related - void OnCurrentTimeUpdateTimerFired(); - void StartCurrentTimeUpdateTimer(); - void StopCurrentTimeUpdateTimer(); - void OnGetFrameDetails(); - - void OnUpdateStates(); - void HandleBufferingMessage(); - void OnPlaybackComplete(); - void UpdateSeekState(bool state); - void OnTimeChanged(); - - // Error handling API - void HandleError(media::MediaPlayerTizen::NetworkState state); - - scoped_ptr demuxer_; - - const scoped_refptr main_loop_; - -#if defined(OS_TIZEN_TV) && !defined(TIZEN_V_3_0) - scoped_refptr audio_session_manager_; -#endif - - // Stats about the media. - bool playing_; - - // Weak pointer passed to media decoder jobs for callbacks. - base::WeakPtrFactory weak_this_; - - // To support Vedio Sink (pixmap). -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - int pixmap_id_; - scoped_refptr efl_pixmap_; - Ecore_X_Damage m_damage; - Ecore_Event_Handler* m_damageHandler; - typedef std::map > EflPixmapMap; - EflPixmapMap efl_pixmaps_map_; -#endif - - // Will allow to listen to |prepare-xid| message only once. - bool is_xwindow_handle_set_; - - // Whenever resolution changes, to change the pixmap - // if Video Playback is backed by |pixmap|. - bool is_backed_by_pixmap; - - GstElement* pipeline_; - GstElement* video_appsrc_; - GstElement* video_parse_; - GstElement* video_decoder_; - GstElement* video_sink_; - GstElement* audio_appsrc_; - GstElement* audio_decoder_; - GstElement* audio_sink_; - GstElement* video_queue_; - GstElement* audio_queue_; - GstElement* audio_parse_; - GstElement* audio_convert_; - GstElement* audio_resampler_; - GstElement* audio_volume_; - GstPad* video_sink_pad_; - bool should_feed_audio_; - bool should_feed_video_; - - int gst_width_; - int gst_height_; - guint32 video_format_; - int media_type; - int bufsize_sn12_; - double play_rate_; - double duration_; - bool is_paused_due_underflow_; - - base::SharedMemory shared_memory; - uint32 shared_memory_size; - base::SharedMemoryHandle foreign_memory_handle; - - int buffered_; - bool is_paused_; - bool is_seeking_; - bool is_demuxer_seeking_; - int audio_buffered_; - int video_buffered_; - - bool is_gst_pipeline_constructed_; - std::deque > audio_buffer_queue_; - std::deque > video_buffer_queue_; - - bool is_download_finished_; - bool is_end_reached_; - bool error_occured_; - - base::RepeatingTimer current_time_update_timer_; - int raw_video_frame_size_; - guint64 video_seek_offset_; - guint64 audio_seek_offset_; - - // When seeked to |x| seconds, |ChunkDemuxer| will send data from - // |x - delta_x| where |x-delta_x| is location of I-Frame. And gstreamer - // decoder is supposed to play media from seek time i.e. |x| seconds. - // But in the gstreamer pipeline created here it starts playing from I-Frame - // i.e. |x-delta_x| but gst-pipeline time starts running from |x|. Hence - // jerky playback is observed for some time during seek. To avoid this, now - // gst-pipeline is also seeked to nearest I-Frame i.e. |x-delta_x|. - bool is_seeking_iframe_; - - DISALLOW_COPY_AND_ASSIGN(MediaSourcePlayerGstreamer); -}; - -} // namespace media - -#endif // MEDIA_BASE_TIZEN_MEDIA_SOURCE_PLAYER_GSTREAMER_H_ diff --git a/tizen_src/impl/media/base/tizen/webaudio_media_codec_info_tizen.h b/tizen_src/impl/media/base/tizen/webaudio_media_codec_info_tizen.h deleted file mode 100644 index 617de5ee4f33..000000000000 --- a/tizen_src/impl/media/base/tizen/webaudio_media_codec_info_tizen.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MEDIA_BASE_TIZEN_WEBAUDIO_MEDIA_CODEC_INFO_TIZEN_H_ -#define MEDIA_BASE_TIZEN_WEBAUDIO_MEDIA_CODEC_INFO_TIZEN_H_ - -namespace media { - -// This structure holds the information about the audio file -// determined by MediaCodec that is needed by the audio decoder to -// create the necessary destination bus. -struct WebAudioMediaCodecInfoTizen { - unsigned long channel_count; - unsigned long sample_rate; - unsigned long number_of_frames; -}; - -} // namespace media -#endif // MEDIA_BASE_TIZEN_WEBAUDIO_MEDIA_CODEC_INFO_TIZEN_H_ \ No newline at end of file diff --git a/tizen_src/impl/media/base/tizen/webmediaplayer_tizen.cc b/tizen_src/impl/media/base/tizen/webmediaplayer_tizen.cc deleted file mode 100644 index a6faa8bbace3..000000000000 --- a/tizen_src/impl/media/base/tizen/webmediaplayer_tizen.cc +++ /dev/null @@ -1,694 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "media/base/tizen/webmediaplayer_tizen.h" - -#include - -#include "cc/blink/web_layer_impl.h" -#include "cc/layers/video_layer.h" -#include "content/renderer/media/render_media_log.h" -#include "content/renderer/media/renderer_gpu_video_accelerator_factories.h" -#include "content/renderer/render_frame_impl.h" -#include "content/renderer/render_thread_impl.h" -#include "media/base/tizen/media_player_tizen.h" -#include "media/base/bind_to_current_loop.h" -#include "media/base/video_frame.h" -#include "media/blink/webmediaplayer_util.h" -#include "third_party/libyuv/include/libyuv/planar_functions.h" -#include "third_party/WebKit/public/platform/WebMediaPlayerClient.h" -#include "wrt/wrt_url_parse.h" - -#define BIND_TO_RENDER_LOOP(function) \ - (DCHECK(main_loop_->BelongsToCurrentThread()), \ - media::BindToCurrentLoop(base::Bind(function, AsWeakPtr()))) - -namespace media { - -// fourcc for gst-video-format -const uint32 GST_VIDEO_SN12 = GST_MAKE_FOURCC('S','N','1','2'); -const uint32 GST_VIDEO_I420 = GST_MAKE_FOURCC('I','4','2','0'); -const uint32 GST_VIDEO_NV12 = GST_MAKE_FOURCC('N','V','1','2'); - -// tile size for SN12 -const uint SN12_TILE_WIDTH = 64; -const uint SN12_TILE_HEIGHT = 32; -const uint SN12_TILE_SIZE = SN12_TILE_WIDTH * SN12_TILE_HEIGHT; - -// Removes query string from URI -GURL GetCleanURL(std::string url) { - // FIXME: Need to consider "app://" scheme. - if (!url.compare(0, 7, "file://")) { - int position = url.find("?"); - if(position != -1) - url.erase(url.begin() + position, url.end()); - } - GURL url_(url); - return url_; -} - -WebMediaPlayerTizen::WebMediaPlayerTizen( - content::RendererMediaPlayerManagerTizen* manager, - blink::WebLocalFrame* frame, - blink::WebMediaPlayerClient* client, - base::WeakPtr delegate, - const WebMediaPlayerParams& params, - content::WrtUrlParseBase* wrt_url_parse) - : frame_(frame), - network_state_(blink::WebMediaPlayer::NetworkStateEmpty), - ready_state_(blink::WebMediaPlayer::ReadyStateHaveNothing), - main_loop_(base::MessageLoopProxy::current()), - media_task_runner_( - content::RenderThreadImpl::current()->GetMediaThreadTaskRunner()), - manager_(manager), - client_(client), - media_log_(new content::RenderMediaLog()), - delegate_(delegate), - compositor_task_runner_( - content::RenderThreadImpl::current()->compositor_message_loop_proxy()), - compositor_(new media::VideoFrameCompositor( - BIND_TO_RENDER_LOOP(&WebMediaPlayerTizen::OnNaturalSizeChanged), - BIND_TO_RENDER_LOOP(&WebMediaPlayerTizen::OnOpacityChanged))), - weak_factory_(this), - gst_video_format_(0), - audio_(false), - video_(false), - current_time_(0), - duration_(0), - is_paused_(true), - is_seeking_(false), - seek_time_(0), - pending_seek_(0), - pending_seek_time_(0), - opaque_(false), - natural_size_(0, 0), - did_loading_progress_(false), - volume_(0), - gpu_factories_(content::RenderThreadImpl::current()->GetGpuFactories()), - encrypted_media_support_( - params.CreateEncryptedMediaPlayerSupport(client)), - wrt_url_parse_(wrt_url_parse) { - DCHECK(manager_); - DCHECK(encrypted_media_support_); - VLOG(1) << "WebMediaPlayerTizen::" << __FUNCTION__; - FrameAvailable_ = false; - // We want to be notified of |main_loop_| destruction. - base::MessageLoop::current()->AddDestructionObserver(this); - - player_id_ = manager_->RegisterMediaPlayer(this); - - // Threaded compositing isn't enabled universally yet. - if (!compositor_task_runner_.get()) - compositor_task_runner_ = base::MessageLoopProxy::current(); - - media_log_->AddEvent( - media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_CREATED)); -} - -WebMediaPlayerTizen::~WebMediaPlayerTizen() { - VLOG(1) << "WebMediaPlayerTizen::" << __FUNCTION__; - if (manager_) { - manager_->DestroyPlayer(player_id_); - manager_->UnregisterMediaPlayer(player_id_); - } - - SetVideoFrameProviderClient(NULL); - client_->setWebLayer(NULL); - if (delegate_.get()) - delegate_->PlayerGone(this); - if (base::MessageLoop::current()) - base::MessageLoop::current()->RemoveDestructionObserver(this); - compositor_task_runner_->DeleteSoon(FROM_HERE, compositor_); - if (media_source_delegate_) { - // Part of |media_source_delegate_| needs to be stopped - // on the media thread. - // Wait until |media_source_delegate_| is fully stopped - // before tearing down other objects. - base::WaitableEvent waiter(false, false); - media_source_delegate_->Stop( - base::Bind(&base::WaitableEvent::Signal, base::Unretained(&waiter))); - waiter.Wait(); - } -} - -void WebMediaPlayerTizen::load(LoadType load_type, - const blink::WebURL& url, - CORSMode cors_mode) { - VLOG(1) << "WebMediaPlayerTizen::" << __FUNCTION__ << " load type - " - << load_type; - int demuxer_client_id = 0; - if (load_type == LoadTypeMediaSource) { - // FIXME: EFL GST-package on desktop cannot handle AAC decoding. - // Disabling MSE for desktop. -#ifdef OS_TIZEN - player_type_ = MEDIA_PLAYER_TYPE_MEDIA_SOURCE; - content::RendererDemuxerTizen* demuxer = - content::RenderThreadImpl::current()->renderer_demuxer(); - demuxer_client_id = demuxer->GetNextDemuxerClientID(); - media_source_delegate_.reset(new content::MediaSourceDelegateTizen( - demuxer, demuxer_client_id, media_task_runner_, media_log_.get())); - SetDecryptorReadyCB set_decryptor_ready_cb = - encrypted_media_support_->CreateSetDecryptorReadyCB(); - Demuxer::NeedKeyCB need_key_cb = - encrypted_media_support_->CreateNeedKeyCB(); - media_source_delegate_->InitializeMediaSource( - base::Bind(&WebMediaPlayerTizen::OnMediaSourceOpened, - weak_factory_.GetWeakPtr()), - need_key_cb, - set_decryptor_ready_cb, - base::Bind(&WebMediaPlayerTizen::SetNetworkState, - weak_factory_.GetWeakPtr()), - base::Bind(&WebMediaPlayerTizen::OnDurationChange, - weak_factory_.GetWeakPtr())); -#else - // Posting Error Message to HTMLMediaElement. - SetNetworkState(WebMediaPlayer::NetworkStateDecodeError); -#endif - } else if (load_type == LoadTypeURL) { - player_type_ = MEDIA_PLAYER_TYPE_URL; - } else { - LOG(ERROR) << "Unsupported load type " << load_type; - return; - } - - blink::WebURL real_url; - if (wrt_url_parse_) - real_url = wrt_url_parse_->parseUrl(url); - else - real_url = url; - - // FIXME: Check URL, Volume for MS. - manager_->Initialize(player_id_, - player_type_, - GetCleanURL(real_url.string().utf8()), - volume_, - demuxer_client_id); -} - -blink::WebMediaPlayer::MediaKeyException -WebMediaPlayerTizen::generateKeyRequest(const blink::WebString& key_system, - const unsigned char* init_data, - unsigned init_data_length) { - DCHECK(main_loop_->BelongsToCurrentThread()); - - return encrypted_media_support_->GenerateKeyRequest( - frame_, key_system, init_data, init_data_length); -} - -blink::WebMediaPlayer::MediaKeyException WebMediaPlayerTizen::addKey( - const blink::WebString& key_system, - const unsigned char* key, - unsigned key_length, - const unsigned char* init_data, - unsigned init_data_length, - const blink::WebString& session_id) { - DCHECK(main_loop_->BelongsToCurrentThread()); - - return encrypted_media_support_->AddKey( - key_system, key, key_length, init_data, init_data_length, session_id); -} - -blink::WebMediaPlayer::MediaKeyException WebMediaPlayerTizen::cancelKeyRequest( - const blink::WebString& key_system, - const blink::WebString& session_id) { - DCHECK(main_loop_->BelongsToCurrentThread()); - - return encrypted_media_support_->CancelKeyRequest(key_system, session_id); -} - -void WebMediaPlayerTizen::setContentDecryptionModule( - blink::WebContentDecryptionModule* cdm) { - DCHECK(main_loop_->BelongsToCurrentThread()); - - encrypted_media_support_->SetContentDecryptionModule(cdm); -} - -void WebMediaPlayerTizen::setContentDecryptionModule( - blink::WebContentDecryptionModule* cdm, - blink::WebContentDecryptionModuleResult result) { - DCHECK(main_loop_->BelongsToCurrentThread()); - - encrypted_media_support_->SetContentDecryptionModule(cdm, result); -} - -void WebMediaPlayerTizen::OnMediaSourceOpened( - blink::WebMediaSource* web_media_source) { - client_->mediaSourceOpened(web_media_source); -} - -void WebMediaPlayerTizen::play() { - manager_->Play(player_id_); - // Has to be updated from |MediaPlayerBridgeGstreamer| but IPC causes delay. - // There are cases were play - pause are fired successively and would fail. - is_paused_ = false; -} - -void WebMediaPlayerTizen::pause() { - manager_->Pause(player_id_, true); - // Has to be updated from |MediaPlayerBridgeGstreamer| but IPC causes delay. - // There are cases were play - pause are fired successively and would fail. - is_paused_ = true; -} - -void WebMediaPlayerTizen::RequestPause() { - pause(); - client_->playbackStateChanged(); -} - -bool WebMediaPlayerTizen::supportsSave() const { - return false; -} - -void WebMediaPlayerTizen::seek(double seconds) { - VLOG(1) << "WebMediaPlayerTizen::" << __FUNCTION__ << " : " << seconds - << " ID " << player_id_; - DCHECK(main_loop_->BelongsToCurrentThread()); - - if (is_seeking_) { - if (seconds == seek_time_) { - if (media_source_delegate_) { - if (!pending_seek_) { - // If using media source demuxer, only suppress redundant seeks if - // there is no pending seek. This enforces that any pending seek that - // results in a demuxer seek is preceded by matching - // CancelPendingSeek() and StartSeek() calls. - return; - } - } else { - // Suppress all redundant seeks if unrestricted by media source - // demuxer API. - pending_seek_ = false; - return; - } - } - - pending_seek_ = true; - pending_seek_time_ = seconds; - if (media_source_delegate_) - media_source_delegate_->CancelPendingSeek( - media::ConvertSecondsToTimestamp(pending_seek_time_)); - // Later, OnSeekComplete will trigger the pending seek. - return; - } - - is_seeking_ = true; - seek_time_ = seconds; - - // Once Chunk demuxer seeks GST seek will be intiated. - if (media_source_delegate_) - media_source_delegate_->StartWaitingForSeek( - media::ConvertSecondsToTimestamp(seek_time_)); - manager_->Seek(player_id_, seek_time_); - - // Draw empty frame during seek. - if (video_) { - gfx::Size size(gst_width_, gst_height_); - scoped_refptr video_frame = VideoFrame::CreateBlackFrame(size); - FrameReady(video_frame); - } -} - -void WebMediaPlayerTizen::setRate(double rate) { - manager_->SetRate(player_id_, rate); -} - -void WebMediaPlayerTizen::setVolume(double volume) { - volume_ = volume; - manager_->SetVolume(player_id_, volume); -} - -blink::WebTimeRanges WebMediaPlayerTizen::buffered() const{ - return buffered_; -} - -blink::WebTimeRanges WebMediaPlayerTizen::seekable() const { - const double seekable_end = duration(); - if (std::isinf(seekable_end)) - return blink::WebTimeRanges(); - - blink::WebTimeRange seekable_range(0.0, seekable_end); - return blink::WebTimeRanges(&seekable_range, 1); -} - -void WebMediaPlayerTizen::paint(blink::WebCanvas* canvas, - const blink::WebRect& rect, - unsigned char alpha, - SkXfermode::Mode mode) { - scoped_refptr video_frame = - GetCurrentFrameFromCompositor(); - - gfx::Rect gfx_rect(rect); - skcanvas_video_renderer_.Paint( - video_frame.get(), canvas, gfx_rect, alpha, - SkXfermode::kSrcOver_Mode, media::VIDEO_ROTATION_0); -} - -bool WebMediaPlayerTizen::hasVideo() const { - return video_; -} - -bool WebMediaPlayerTizen::hasAudio() const { - return audio_; -} - -blink::WebSize WebMediaPlayerTizen::naturalSize() const { - return blink::WebSize(natural_size_); -} - -bool WebMediaPlayerTizen::paused() const { - return is_paused_; -} - -bool WebMediaPlayerTizen::seeking() const { - return is_seeking_; -} - -double WebMediaPlayerTizen::duration() const { - return duration_; -} - -double WebMediaPlayerTizen::currentTime() const { - if (seeking()) - return pending_seek_ ? pending_seek_time_ : seek_time_; - return current_time_; -} - -blink::WebMediaPlayer::NetworkState WebMediaPlayerTizen::networkState() const { - return network_state_; -} - -blink::WebMediaPlayer::ReadyState WebMediaPlayerTizen::readyState() const { - return ready_state_; -} - -bool WebMediaPlayerTizen::didLoadingProgress() { - if (did_loading_progress_) { - did_loading_progress_ = false; - return true; - } - return false; -} - -bool WebMediaPlayerTizen::hasSingleSecurityOrigin() const { - return true; -} - -bool WebMediaPlayerTizen::didPassCORSAccessCheck() const { - return false; -} - -double WebMediaPlayerTizen::mediaTimeForTimeValue(double timeValue) const { - return media::ConvertSecondsToTimestamp(timeValue).InSecondsF(); -} - -void WebMediaPlayerTizen::SetVideoFrameProviderClient( - cc::VideoFrameProvider::Client* client) { - // This is called from both the main renderer thread and the compositor - // thread (when the main thread is blocked). - compositor_->SetVideoFrameProviderClient(client); -} - -scoped_refptrWebMediaPlayerTizen::GetCurrentFrame() { - scoped_refptr current_frame = - GetCurrentFrameFromCompositor(); - return current_frame; -} - -void WebMediaPlayerTizen::SetReadyState(WebMediaPlayer::ReadyState state) { - ready_state_ = state; - client_->readyStateChanged(); -} - -void WebMediaPlayerTizen::SetNetworkState(WebMediaPlayer::NetworkState state) { - network_state_ = state; - client_->networkStateChanged(); -} - -void WebMediaPlayerTizen::OnNewFrameAvailable(base::SharedMemoryHandle Handle, - uint32 yuv_size, - base::TimeDelta timestamp) { - base::SharedMemory shared_memory(Handle, false); - shared_memory.Map(yuv_size); - uint8* const yuv_buffer = static_cast(shared_memory.memory()); - - gfx::Size size(gst_width_, gst_height_); - scoped_refptr video_frame = - VideoFrame::CreateFrame( - VideoFrame::YV12, size, gfx::Rect(size), size, timestamp); - - // decoded format is SN12 on Tizen device - // video format converted from SN12 to YV12 - uint8* gst_buf = yuv_buffer; - switch(gst_video_format_) { - case GST_VIDEO_I420: { - const uint c_frm_size = yuv_size / 6; - const uint y_frm_size = c_frm_size << 2; // * 4; - // U Plane buffer. - uint8* gst_buf_u = gst_buf + y_frm_size; - // V Plane buffer. - uint8* gst_buf_v = gst_buf_u + c_frm_size; - - - // Get the videoframe stride size. - // Calculate the gstreamer buffer stride size. - const uint uv_rows = video_frame.get()->rows(VideoFrame::kUPlane); - const uint gst_stride = c_frm_size / uv_rows; - - libyuv::I420Copy(gst_buf, 2 * gst_stride, - gst_buf_u, gst_stride, - gst_buf_v, gst_stride, - video_frame.get()->data(VideoFrame::kYPlane), - video_frame.get()->stride(VideoFrame::kYPlane), - video_frame.get()->data(VideoFrame::kUPlane), - video_frame.get()->stride(VideoFrame::kUPlane), - video_frame.get()->data(VideoFrame::kVPlane), - video_frame.get()->stride(VideoFrame::kVPlane), - gst_width_, gst_height_); - break; - } - case GST_VIDEO_SN12: { - //const uint tile_w = (gst_width_ - 1) / SN12_TILE_WIDTH + 1; - //const uint tile_w_align = (tile_w + 1) & ~1; - //const uint tile_h_luma = (gst_height_ - 1) / SN12_TILE_HEIGHT + 1; - const uint tile_w_align = ((gst_width_ - 1) / SN12_TILE_WIDTH + 2) & ~1; - const uint tile_luma_stride = tile_w_align * SN12_TILE_WIDTH; - uint luma_size = SN12_TILE_SIZE * tile_w_align - * ((gst_height_-1)/SN12_TILE_HEIGHT + 1); - - uint8* y_frm = video_frame.get()->data(VideoFrame::kYPlane); - const uint y_stride = video_frame.get()->stride(VideoFrame::kYPlane); - - // actually copy and convert luma buffer - for(int i=0; idata(VideoFrame::kUPlane); - uint8* v_frm = video_frame.get()->data(VideoFrame::kVPlane); - const uint uv_stride = video_frame.get()->stride(VideoFrame::kUPlane); - const uint uv_rows = video_frame.get()->rows(VideoFrame::kUPlane); - - // actually copy and convert chroma buffer - for(uint row=0; rowdata(VideoFrame::kYPlane), - gst_buf, y_frm_size); - - gst_buf += y_frm_size; - uint8* gst_buf2 = gst_buf + 1; - uint8* u_plane = video_frame.get()->data(VideoFrame::kUPlane); - uint8* v_plane = video_frame.get()->data(VideoFrame::kVPlane); - - for(uint i = 0; i < c_frm_size; i++){ - // kUPlane - u_plane[i] = gst_buf[i * 2]; - // kVPlane - v_plane[i] = gst_buf2[i * 2]; - } - break; - } - default: { - LOG(ERROR) << "WebMediaPlayerTizen::" << __FUNCTION__ - << " not supported video format"; - break; - } - } - - shared_memory.Close(); - FrameReady(video_frame); -} - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) -// FIXME: Graphics team need to merge painting of Video-Frame on to 2d-canvas -// from m34. -void WebMediaPlayerTizen::OnPlatformSurfaceUpdated( - int pixmap_id, - base::TimeDelta timestamp) { - gfx::Size size(gst_width_, gst_height_); - scoped_refptr video_frame = VideoFrame::WrapNativePixmap( - VideoFrame::NATIVE_PIXMAP, size, gfx::Rect(size), size, - timestamp, pixmap_id); - FrameReady(video_frame); -} -#endif - -void WebMediaPlayerTizen::FrameReady( - const scoped_refptr& frame) { - compositor_task_runner_->PostTask( - FROM_HERE, - base::Bind(&media::VideoFrameCompositor::UpdateCurrentFrame, - base::Unretained(compositor_), - frame)); -} -void WebMediaPlayerTizen::OnMediaDataChange(int format, int height, int width, int media) { - gst_video_format_ = static_cast(format); - gst_height_ = height; - gst_width_ = width; - audio_ = media & media::MEDIA_AUDIO_MASK ? true : false; - video_ = media & media::MEDIA_VIDEO_MASK ? true : false; - natural_size_ = gfx::Size(width, height); - SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); - if (hasVideo() && !video_weblayer_.get()) { - scoped_refptr layer = - cc::VideoLayer::Create(compositor_, media::VIDEO_ROTATION_0); - video_weblayer_.reset(new cc_blink::WebLayerImpl(layer)); - video_weblayer_->setOpaque(opaque_); - client_->setWebLayer(video_weblayer_.get()); - } -} - -void WebMediaPlayerTizen::OnTimeChanged() { - is_seeking_ = false; - - // Handling pending seek for ME. For MSE |CancelPendingSeek| - // will handle the pending seeks. - if (!media_source_delegate_ && pending_seek_) { - pending_seek_ = false; - seek(pending_seek_time_); - return; - } - client_->timeChanged(); -} - -void WebMediaPlayerTizen::OnDurationChange(double duration) { - duration_ = duration; - client_->durationChanged(); -} - -void WebMediaPlayerTizen::OnNaturalSizeChanged(gfx::Size size) { - DCHECK(main_loop_->BelongsToCurrentThread()); - DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing); - TRACE_EVENT0("media", "WebMediaPlayerTizen::OnNaturalSizeChanged"); - media_log_->AddEvent( - media_log_->CreateVideoSizeSetEvent(size.width(), size.height())); - natural_size_ = size; - - client_->sizeChanged(); -} - -void WebMediaPlayerTizen::OnOpacityChanged(bool opaque) { - DCHECK(main_loop_->BelongsToCurrentThread()); - DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing); - - opaque_ = opaque; - if (video_weblayer_) - video_weblayer_->setOpaque(opaque_); -} - -static void GetCurrentFrameAndSignal( - media::VideoFrameCompositor* compositor, - scoped_refptr* video_frame_out, - base::WaitableEvent* event) { - TRACE_EVENT0("media", "GetCurrentFrameAndSignal"); - *video_frame_out = compositor->GetCurrentFrame(); - event->Signal(); -} - -scoped_refptr - WebMediaPlayerTizen::GetCurrentFrameFromCompositor() { - TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor"); - - if (compositor_task_runner_->BelongsToCurrentThread()) - return compositor_->GetCurrentFrame(); - - // Use a posted task and waitable event instead of a lock otherwise - // WebGL/Canvas can see different content than what the compositor is seeing. - scoped_refptr video_frame; - base::WaitableEvent event(false, false); - compositor_task_runner_->PostTask(FROM_HERE, - base::Bind(&GetCurrentFrameAndSignal, - base::Unretained(compositor_), - &video_frame, - &event)); - event.Wait(); - return video_frame; -} - -void WebMediaPlayerTizen::OnTimeUpdate(double current_time) { - current_time_ = current_time; -} - -void WebMediaPlayerTizen::OnBufferUpdate( - std::vector buffer_range) { - media::Ranges time_ranges; - std::vector::iterator tr_it; - for ( tr_it = buffer_range.begin(); tr_it != buffer_range.end(); ++tr_it) { - time_ranges.Add( - base::TimeDelta::FromMicroseconds((*tr_it).start), - base::TimeDelta::FromMicroseconds((*tr_it).end)); - } - blink::WebTimeRanges web_ranges(ConvertToWebTimeRanges(time_ranges)); - buffered_.swap(web_ranges); - did_loading_progress_ = true; -} - -void WebMediaPlayerTizen::OnPauseStateChange(bool state) { - VLOG(1) << "WebMediaPlayerTizen::" << __FUNCTION__ << " state:" << state; - is_paused_ = state; - if (delegate_.get()) { - if(is_paused_) - delegate_->DidPause(this); - else - delegate_->DidPlay(this); - } -} - -void WebMediaPlayerTizen::OnSeekStateChange(bool state) { - VLOG(1) << "WebMediaPlayerTizen::" << __FUNCTION__ << " state:" << state - << " ID " << player_id_; - is_seeking_ = state; - // Draw empty frame during seek. - if (video_ && is_seeking_) { - gfx::Size size(gst_width_, gst_height_); - scoped_refptr video_frame = VideoFrame::CreateBlackFrame(size); - FrameReady(video_frame); - } -} - -void WebMediaPlayerTizen::OnRequestSeek(double seek_time) { - client_->requestSeek(seek_time); -} - -} // namespace media diff --git a/tizen_src/impl/media/base/tizen/webmediaplayer_tizen.h b/tizen_src/impl/media/base/tizen/webmediaplayer_tizen.h deleted file mode 100644 index cb1a12a1aa83..000000000000 --- a/tizen_src/impl/media/base/tizen/webmediaplayer_tizen.h +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright 2014 Samsung Electronics Inc. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_RENDERER_MEDIA_TIZEN_WEBMEDIAPLAYER_TIZEN_H_ -#define CONTENT_RENDERER_MEDIA_TIZEN_WEBMEDIAPLAYER_TIZEN_H_ - -#include "base/message_loop/message_loop.h" -#include "cc/layers/video_frame_provider_client_impl.h" -#include "content/renderer/media/tizen/media_source_delegate_tizen.h" -#include "content/renderer/media/tizen/renderer_media_player_manager_tizen.h" -#include "media/blink/video_frame_compositor.h" -#include "media/blink/webmediaplayer_params.h" -#include "media/filters/skcanvas_video_renderer.h" - -namespace blink { -class WebLocalFrame; -} - -namespace cc_blink { -class WebLayerImpl; -} - -namespace content { -class RendererMediaPlayerManagerTizen; -class WrtUrlParseBase; -} - -namespace media { - -class GpuVideoAcceleratorFactories; -class WebMediaPlayerDelegate; - -// This class implements blink::WebMediaPlayer by keeping the tizen -// media player in the browser process. It listens to all the status changes -// sent from the browser process and sends playback controls to the media -// player. -class WebMediaPlayerTizen - : public blink::WebMediaPlayer, - public cc::VideoFrameProvider, - public base::MessageLoop::DestructionObserver, - public base::SupportsWeakPtr { - public: - // Construct a WebMediaPlayerTizen object. This class communicates - // with the WebMediaPlayerTizen object in the browser process through - // |proxy|. - WebMediaPlayerTizen( - content::RendererMediaPlayerManagerTizen* manager, - blink::WebLocalFrame* frame, - blink::WebMediaPlayerClient* client, - base::WeakPtr delegate, - const WebMediaPlayerParams& params, - content::WrtUrlParseBase* wrt_url_parse); - virtual ~WebMediaPlayerTizen(); - - // blink::WebMediaPlayer implementation. - virtual void load(LoadType load_type, - const blink::WebURL& url, - CORSMode cors_mode) override; - - // Playback controls. - virtual void play() override; - virtual void pause() override; - virtual bool supportsSave() const override; - virtual void seek(double seconds) override; - virtual void setRate(double) override; - virtual void setVolume(double) override; - virtual blink::WebTimeRanges buffered() const override; - virtual blink::WebTimeRanges seekable() const override; - - virtual void paint(blink::WebCanvas*, - const blink::WebRect&, - unsigned char alpha, - SkXfermode::Mode) override; - - // True if the loaded media has a playable video/audio track. - virtual bool hasVideo() const override; - virtual bool hasAudio() const override; - - // Dimension of the video. - virtual blink::WebSize naturalSize() const override; - - // Getters of playback state. - virtual bool paused() const override; - virtual bool seeking() const override; - virtual double duration() const override; - virtual double currentTime() const override; - - // Internal states of loading and network. - virtual NetworkState networkState() const override; - virtual ReadyState readyState() const override; - - virtual bool didLoadingProgress() override; - - virtual bool hasSingleSecurityOrigin() const override; - virtual bool didPassCORSAccessCheck() const override; - - virtual double mediaTimeForTimeValue(double timeValue) const override; - - virtual unsigned decodedFrameCount() const override { return 0;}; - virtual unsigned droppedFrameCount() const override{ return 0;};; - virtual unsigned audioDecodedByteCount() const override{ return 0;};; - virtual unsigned videoDecodedByteCount() const override{ return 0;};; - - // cc::VideoFrameProvider implementation. - virtual void SetVideoFrameProviderClient( - cc::VideoFrameProvider::Client* client) override; - virtual scoped_refptr GetCurrentFrame() override; - virtual void PutCurrentFrame( - const scoped_refptr& frame) override {}; - - // Method inherited from DestructionObserver. - virtual void WillDestroyCurrentMessageLoop() override {}; - - virtual MediaKeyException generateKeyRequest( - const blink::WebString& key_system, - const unsigned char* init_data, - unsigned init_data_length); - - virtual MediaKeyException addKey(const blink::WebString& key_system, - const unsigned char* key, - unsigned key_length, - const unsigned char* init_data, - unsigned init_data_length, - const blink::WebString& session_id); - - virtual MediaKeyException cancelKeyRequest( - const blink::WebString& key_system, - const blink::WebString& session_id); - - // TODO(jrummell): Remove this method once Blink updated to use the other - // method. - virtual void setContentDecryptionModule( - blink::WebContentDecryptionModule* cdm); - virtual void setContentDecryptionModule( - blink::WebContentDecryptionModule* cdm, - blink::WebContentDecryptionModuleResult result); - - void SetReadyState(WebMediaPlayer::ReadyState state); - void SetNetworkState(WebMediaPlayer::NetworkState state); - - void OnNewFrameAvailable(base::SharedMemoryHandle foreign_memory_handle, - uint32 length, base::TimeDelta timestamp); - -#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT) - void OnPlatformSurfaceUpdated(int pixmap_id, base::TimeDelta timestamp); -#endif - - void OnMediaDataChange(int format, int height, int width, int media); - void OnDurationChange(double duration); - void OnTimeUpdate(double current_time); - void OnBufferUpdate( - std::vector buffer_range); - void OnTimeChanged(); - void OnPauseStateChange(bool state); - void OnSeekStateChange(bool state); - void OnRequestSeek(double seek_time); - - void OnMediaSourceOpened(blink::WebMediaSource* web_media_source); - void OnDemuxerSeekDone(); - - void RequestPause(); - - private: - void OnNaturalSizeChanged(gfx::Size size); - void OnOpacityChanged(bool opaque); - - // Returns the current video frame from |compositor_|. Blocks until the - // compositor can return the frame. - scoped_refptr GetCurrentFrameFromCompositor(); - - // Called whenever there is new frame to be painted. - void FrameReady(const scoped_refptr& frame); - - blink::WebLocalFrame* frame_; - - blink::WebMediaPlayer::NetworkState network_state_; - blink::WebMediaPlayer::ReadyState ready_state_; - - // Message loops for posting tasks on Chrome's main thread. Also used - // for DCHECKs so methods calls won't execute in the wrong thread. - const scoped_refptr main_loop_; - scoped_refptr media_task_runner_; - - // Manager for managing this object and for delegating method calls on - // Render Thread. - content::RendererMediaPlayerManagerTizen* manager_; - - blink::WebMediaPlayerClient* client_; - - scoped_refptr media_log_; - - base::WeakPtr delegate_; - - // The compositor layer for displaying the video content when using - // composited playback. - scoped_ptr video_weblayer_; - - - // Video rendering members. - scoped_refptr compositor_task_runner_; - media::VideoFrameCompositor* compositor_; - media::SkCanvasVideoRenderer skcanvas_video_renderer_; - - base::WeakPtrFactory weak_factory_; - scoped_ptr media_source_delegate_; - MediaPlayerHostMsg_Initialize_Type player_type_; - - // Player ID assigned by the |manager_|. - int player_id_; - - uint32 gst_video_format_; - int gst_width_; - int gst_height_; - - bool FrameAvailable_; - bool audio_; - bool video_; - - double current_time_; - double duration_; - bool is_paused_; - - bool is_seeking_; - double seek_time_; - bool pending_seek_; - double pending_seek_time_; - - // Whether the video is known to be opaque or not. - bool opaque_; - - gfx::Size natural_size_; - blink::WebTimeRanges buffered_; - mutable bool did_loading_progress_; - double volume_; - - // Factories for supporting video accelerators. May be null. - scoped_refptr gpu_factories_; - scoped_ptr encrypted_media_support_; - content::WrtUrlParseBase* wrt_url_parse_; - - DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerTizen); -}; - -} // namespace media - -#endif // CONTENT_RENDERER_MEDIA_TIZEN_WEBMEDIAPLAYER_TIZEN_H_ diff --git a/tizen_src/impl/media/video/capture/tizen/video_capture_device_factory_tizen.cc b/tizen_src/impl/media/video/capture/tizen/video_capture_device_factory_tizen.cc deleted file mode 100644 index 5ebec8b237a6..000000000000 --- a/tizen_src/impl/media/video/capture/tizen/video_capture_device_factory_tizen.cc +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright 2014 The Samsung 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 "media/video/capture/tizen/video_capture_device_factory_tizen.h" - -#include - -#include "media/video/capture/tizen/video_capture_device_tizen.h" - -namespace { - -enum { kMaxWidth = 1280 }; -enum { kMaxHeight = 720 }; -enum { kMaxFramerate = CAMERA_ATTR_FPS_30 }; - -media::VideoPixelFormat toChromiumType(camera_pixel_format_e e) { - switch (e) { - case CAMERA_PIXEL_FORMAT_NV12: - return media::PIXEL_FORMAT_NV12; - case CAMERA_PIXEL_FORMAT_NV21: - return media::PIXEL_FORMAT_NV21; - case CAMERA_PIXEL_FORMAT_YUYV: - return media::PIXEL_FORMAT_YUY2; - case CAMERA_PIXEL_FORMAT_RGB888: - return media::PIXEL_FORMAT_RGB24; - case CAMERA_PIXEL_FORMAT_UYVY: - return media::PIXEL_FORMAT_UYVY; - case CAMERA_PIXEL_FORMAT_ARGB: - return media::PIXEL_FORMAT_ARGB; - case CAMERA_PIXEL_FORMAT_I420: - return media::PIXEL_FORMAT_I420; - case CAMERA_PIXEL_FORMAT_YV12: - return media::PIXEL_FORMAT_YV12; - case CAMERA_PIXEL_FORMAT_JPEG: - return media::PIXEL_FORMAT_MJPEG; - default: - NOTREACHED(); - } - return media::PIXEL_FORMAT_UNKNOWN; -} - -bool OnCameraSupportedPreviewResolution( - int width, int height, void* user_data) { - std::vector* sizes = - static_cast< std::vector* >(user_data); - DCHECK(sizes); - - if ((width > kMaxWidth && height > kMaxHeight) || - (height > kMaxWidth && width > kMaxHeight)) { - return true; - } - - sizes->push_back(gfx::Size(width, height)); - - return true; -} - -bool OnCameraSupportedPreviewFormat( - camera_pixel_format_e format, void* user_data) { - std::vector* list_format = - static_cast< std::vector* >(user_data); - DCHECK(list_format); - - list_format->push_back(toChromiumType(format)); - - return true; -} - -bool OnCameraSupportedFPS(camera_attr_fps_e fps, void* user_data) { - std::vector* list_fps = static_cast< std::vector* >(user_data); - DCHECK(list_fps); - if (CAMERA_ATTR_FPS_AUTO != fps && kMaxFramerate >= fps) { - // AUTO format is not defined on Chromium, so skip. - list_fps->push_back(static_cast(fps)); - } - - return true; -} - -void GenerateChromiumVideoCaptureFormat( - const std::vector& frame_sizes, - const std::vector& fps, - const std::vector& formats, - std::vector& outSupportedFormats) { - for (auto itrS = frame_sizes.begin(); itrS != frame_sizes.end(); itrS++) { - for (auto itrFPS = fps.begin(); itrFPS != fps.end(); itrFPS++) { - for (auto itrFMT = formats.begin(); itrFMT != formats.end(); itrFMT++) { - media::VideoCaptureFormat format; - format.frame_size = *itrS; - format.frame_rate = *itrFPS; - format.pixel_format = *itrFMT; - outSupportedFormats.push_back(format); - - LOG(INFO) << __FUNCTION__ - << " frame_size:" << format.frame_size.width() << "X" << format.frame_size.height() - << " frame_rate:" << format.frame_rate - << " pixel_format:" << format.pixel_format; - } - } - } -} - -class CameraHandle final { - public: - explicit CameraHandle(const media::VideoCaptureDevice::Name& dev) - : camera_handle_(NULL) { - if (!dev.id().empty()) - if (CAMERA_ERROR_NONE != camera_create( - media::VideoCaptureDeviceTizen::DeviceNameToCameraId(dev), - &camera_handle_)) { - camera_handle_ = NULL; - LOG(ERROR) << "Cannot create camera"; - } - } - - CameraHandle() - : camera_handle_(NULL) { - if (CAMERA_ERROR_NONE != camera_create(CAMERA_DEVICE_CAMERA0, &camera_handle_)) { - camera_handle_ = NULL; - LOG(ERROR) << "Cannot create camera"; - } - } - - ~CameraHandle() { - if (camera_handle_ != NULL) - camera_destroy(camera_handle_); - } - - bool IsValid() const { - return camera_handle_ != NULL; - } - - void GetDeviceSupportedFormats( - media::VideoCaptureFormats& supported_formats) const { - std::vector supported_frame_sizes; - std::vector supported_frame_rates; - std::vector supported_pixel_formats; - - if (!IsValid()) { - LOG(ERROR) << "Cannot use camera"; - return; - } - - if (CAMERA_ERROR_NONE != camera_foreach_supported_preview_resolution( - camera_handle_, - OnCameraSupportedPreviewResolution, - &supported_frame_sizes)) { - LOG(ERROR) << "Cannot get the supported resolutions for camera"; - return; - } - - if (CAMERA_ERROR_NONE != camera_foreach_supported_preview_format( - camera_handle_, - OnCameraSupportedPreviewFormat, - &supported_pixel_formats)) { - LOG(ERROR) << "Cannot get the supported formats for camera"; - return; - } - - if (CAMERA_ERROR_NONE != camera_attr_foreach_supported_fps( - camera_handle_, - OnCameraSupportedFPS, - &supported_frame_rates)) { - LOG(ERROR) << "Cannot get the supported FPS for camera"; - return; - } - supported_formats.clear(); - GenerateChromiumVideoCaptureFormat(supported_frame_sizes, - supported_frame_rates, - supported_pixel_formats, - supported_formats); - } - - int GetDeviceCounts() const { - int device_count = 0; - if (CAMERA_ERROR_NONE != - camera_get_device_count(camera_handle_, &device_count)) { - device_count = 0; - LOG(ERROR) << "Cannot read camera count"; - } - return device_count; - } - - private: - camera_h camera_handle_; -}; - -} // namespace - -namespace media { - -VideoCaptureDeviceFactoryTizen::VideoCaptureDeviceFactoryTizen( - scoped_refptr ui_task_runner) - : ui_task_runner_(ui_task_runner) { -} - -VideoCaptureDeviceFactoryTizen::~VideoCaptureDeviceFactoryTizen() { -} - -scoped_ptr VideoCaptureDeviceFactoryTizen::Create( - const VideoCaptureDevice::Name& name) { - DCHECK(thread_checker_.CalledOnValidThread()); - - return scoped_ptr(new VideoCaptureDeviceTizen(name)); -} - -void VideoCaptureDeviceFactoryTizen::GetDeviceNames( - VideoCaptureDevice::Names* const device_names) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(device_names->empty()); - VideoCaptureDevice::Name primary_camera( - VideoCaptureDeviceTizen::kBackCameraName, - VideoCaptureDeviceTizen::kBackCameraId); - CameraHandle camera_handle; - - if (!camera_handle.IsValid()) { - LOG(ERROR) << "Cannot use camera"; - return; - } - - int device_count = camera_handle.GetDeviceCounts(); - if (device_count == 0) { - LOG(ERROR) << "No camera on this device."; - return; - } - - device_names->push_back(primary_camera); - if (device_count == 2) { - VideoCaptureDevice::Name secondary_camera( - VideoCaptureDeviceTizen::kFrontCameraName, - VideoCaptureDeviceTizen::kFrontCameraId); - device_names->push_back(secondary_camera); - } -} - -void VideoCaptureDeviceFactoryTizen::GetDeviceSupportedFormats( - const VideoCaptureDevice::Name& device, - VideoCaptureFormats* supported_formats) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(supported_formats != NULL); - CameraHandle camera_handle; - camera_handle.GetDeviceSupportedFormats(*supported_formats); -} - -} // namespace media diff --git a/tizen_src/impl/media/video/capture/tizen/video_capture_device_factory_tizen.h b/tizen_src/impl/media/video/capture/tizen/video_capture_device_factory_tizen.h deleted file mode 100644 index 094ae5458a68..000000000000 --- a/tizen_src/impl/media/video/capture/tizen/video_capture_device_factory_tizen.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2014 The Samsung Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Implementation of a VideoCaptureDeviceFactoryTizen class. - -#ifndef MEDIA_VIDEO_CAPTURE_TIZEN_VIDEO_CAPTURE_DEVICE_FACTORY_TIZEN_H_ -#define MEDIA_VIDEO_CAPTURE_TIZEN_VIDEO_CAPTURE_DEVICE_FACTORY_TIZEN_H_ - -#include "media/video/capture/video_capture_device_factory.h" - -namespace media { - -// Extension of VideoCaptureDeviceFactory to create and manipulate Tizen -// devices. -class MEDIA_EXPORT VideoCaptureDeviceFactoryTizen - : public VideoCaptureDeviceFactory { - public: - explicit VideoCaptureDeviceFactoryTizen( - scoped_refptr ui_task_runner); - ~VideoCaptureDeviceFactoryTizen() override; - - scoped_ptr Create( - const VideoCaptureDevice::Name& device_name) override; - void GetDeviceNames(VideoCaptureDevice::Names* device_names) override; - void GetDeviceSupportedFormats( - const VideoCaptureDevice::Name& device, - VideoCaptureFormats* supported_formats) override; - - private: - scoped_refptr ui_task_runner_; - - DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceFactoryTizen); -}; - -} // namespace media - -#endif // MEDIA_VIDEO_CAPTURE_TIZEN_VIDEO_CAPTURE_DEVICE_FACTORY_TIZEN_H_ diff --git a/tizen_src/impl/media/video/capture/tizen/video_capture_device_factory_tizen_helper.cc b/tizen_src/impl/media/video/capture/tizen/video_capture_device_factory_tizen_helper.cc deleted file mode 100644 index 0054beda6fa2..000000000000 --- a/tizen_src/impl/media/video/capture/tizen/video_capture_device_factory_tizen_helper.cc +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2014 The Samsung Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#if defined(TIZEN_VIDEO_CAPTURE_SUPPORT) -#include "media/video/capture/tizen/video_capture_device_factory_tizen.h" -#else -#include "media/video/capture/linux/video_capture_device_factory_linux.h" -#endif - -namespace media { - -scoped_ptr CreateVideoCaptureDeviceFactoryTizen( - scoped_refptr ui_task_runner) { -#if defined(TIZEN_VIDEO_CAPTURE_SUPPORT) - return scoped_ptr( - new VideoCaptureDeviceFactoryTizen(ui_task_runner)); -#else - return scoped_ptr( - new VideoCaptureDeviceFactoryLinux(ui_task_runner)); -#endif -} - -} // namespace media diff --git a/tizen_src/impl/media/video/capture/tizen/video_capture_device_tizen.cc b/tizen_src/impl/media/video/capture/tizen/video_capture_device_tizen.cc deleted file mode 100644 index 914178c99e02..000000000000 --- a/tizen_src/impl/media/video/capture/tizen/video_capture_device_tizen.cc +++ /dev/null @@ -1,336 +0,0 @@ -// Copyright (c) 2012 The Samsung 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 "media/video/capture/tizen/video_capture_device_tizen.h" - -#include "eweb_view.h" - -//#define WEBRTC_DEBUG_DUMPFILE - -#if defined(WEBRTC_DEBUG_DUMPFILE) -#include -#include -int fd; -#endif - -namespace { - -enum { kMjpegWidth = 640 }; -enum { kMjpegHeight = 480 }; -enum { kTypicalFramerate = 30 }; - -camera_pixel_format_e toCapiType(media::VideoPixelFormat e) { - switch (e) { - case media::PIXEL_FORMAT_NV12: - return CAMERA_PIXEL_FORMAT_NV12; - case media::PIXEL_FORMAT_NV21: - return CAMERA_PIXEL_FORMAT_NV21; - case media::PIXEL_FORMAT_YUY2: - return CAMERA_PIXEL_FORMAT_YUYV; - case media::PIXEL_FORMAT_RGB24: - return CAMERA_PIXEL_FORMAT_RGB888; - case media::PIXEL_FORMAT_UYVY: - return CAMERA_PIXEL_FORMAT_UYVY; - case media::PIXEL_FORMAT_ARGB: - return CAMERA_PIXEL_FORMAT_ARGB; - case media::PIXEL_FORMAT_I420: - return CAMERA_PIXEL_FORMAT_I420; - case media::PIXEL_FORMAT_YV12: - return CAMERA_PIXEL_FORMAT_YV12; - case media::PIXEL_FORMAT_MJPEG: - return CAMERA_PIXEL_FORMAT_JPEG; - default: - NOTREACHED(); - } - return CAMERA_PIXEL_FORMAT_INVALID; -} - -std::string toString(camera_pixel_format_e e) { - switch (e) { - case CAMERA_PIXEL_FORMAT_NV12: - return std::string("CAMERA_PIXEL_FORMAT_NV12"); - case CAMERA_PIXEL_FORMAT_NV12T: - return std::string("CAMERA_PIXEL_FORMAT_NV12T"); - case CAMERA_PIXEL_FORMAT_NV16: - return std::string("CAMERA_PIXEL_FORMAT_NV12T"); - case CAMERA_PIXEL_FORMAT_NV21: - return std::string("CAMERA_PIXEL_FORMAT_NV21"); - case CAMERA_PIXEL_FORMAT_YUYV: - return std::string("CAMERA_PIXEL_FORMAT_YUYV"); - case CAMERA_PIXEL_FORMAT_UYVY: - return std::string("CAMERA_PIXEL_FORMAT_YUYV"); - case CAMERA_PIXEL_FORMAT_422P: - return std::string("CAMERA_PIXEL_FORMAT_422P"); - case CAMERA_PIXEL_FORMAT_I420: - return std::string("CAMERA_PIXEL_FORMAT_I420"); - case CAMERA_PIXEL_FORMAT_YV12: - return std::string("CAMERA_PIXEL_FORMAT_YV12"); - case CAMERA_PIXEL_FORMAT_RGB565: - return std::string("CAMERA_PIXEL_FORMAT_RGB565"); - case CAMERA_PIXEL_FORMAT_RGB888: - return std::string("CAMERA_PIXEL_FORMAT_RGB888"); - case CAMERA_PIXEL_FORMAT_RGBA: - return std::string("CAMERA_PIXEL_FORMAT_RGBA"); - case CAMERA_PIXEL_FORMAT_ARGB: - return std::string("CAMERA_PIXEL_FORMAT_ARGB"); - case CAMERA_PIXEL_FORMAT_JPEG: - return std::string("CAMERA_PIXEL_FORMAT_JPEG"); - default: - case CAMERA_PIXEL_FORMAT_INVALID: - return std::string("CAMERA_PIXEL_FORMAT_JPEG"); - break; - } - return std::string(); -} - -bool OnPreviewFormat( - camera_pixel_format_e format, void* user_data) { - std::vector* list_format = - static_cast< std::vector* >(user_data); - DCHECK(list_format); - - list_format->push_back(format); - - return true; -} - -} // unnamed namespace - -namespace media { - -const std::string VideoCaptureDeviceTizen::kFrontCameraName = "front"; -const std::string VideoCaptureDeviceTizen::kBackCameraName = "back"; -const std::string VideoCaptureDeviceTizen::kFrontCameraId = "1"; -const std::string VideoCaptureDeviceTizen::kBackCameraId = "0"; - -const std::string VideoCaptureDevice::Name::GetModel() const { - return "tizen camera"; -} - -VideoCaptureDeviceTizen::VideoCaptureDeviceTizen(const Name& device_name) - : state_(kIdle), - device_name_(device_name), - worker_("VideoCapture"), - buffer_(), - camera_(NULL) { -#if defined(WEBRTC_DEBUG_DUMPFILE) - LOG(INFO) << __FUNCTION__ << " DUMP OUTPUT to file: /opt/usr/dump.yuv"; - fd = open( "/opt/usr/dump.yuv", O_WRONLY | O_CREAT | O_EXCL, 0644); -#endif -} - -VideoCaptureDeviceTizen::~VideoCaptureDeviceTizen() { - state_ = kIdle; - DCHECK(!worker_.IsRunning()); -} - -void VideoCaptureDeviceTizen::AllocateAndStart( - const VideoCaptureParams& params, - scoped_ptr client) { - DCHECK(!worker_.IsRunning()); - worker_.Start(); - worker_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&VideoCaptureDeviceTizen::OnAllocateAndStart, - base::Unretained(this), - params.requested_format.frame_size.width(), - params.requested_format.frame_size.height(), - params.requested_format.frame_rate, - params.requested_format.pixel_format, - base::Passed(&client))); -} - -void VideoCaptureDeviceTizen::StopAndDeAllocate() { - DCHECK(worker_.IsRunning()); - worker_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&VideoCaptureDeviceTizen::OnStopAndDeAllocate, - base::Unretained(this))); - worker_.Stop(); - DeAllocateVideoBuffers(); -} - -camera_device_e VideoCaptureDeviceTizen::DeviceNameToCameraId( - const VideoCaptureDevice::Name& device_name) { - if (kBackCameraId == device_name.id()) { - return CAMERA_DEVICE_CAMERA0; - } else if (kFrontCameraId == device_name.id()) { - return CAMERA_DEVICE_CAMERA1; - } else { - NOTREACHED(); - } - return static_cast(-1); -} - -void VideoCaptureDeviceTizen::OnCameraCaptured(camera_preview_data_s* frame, - void* data) { - VideoCaptureDeviceTizen* self = static_cast(data); - camera_attr_fps_e current_fps = - static_cast(kTypicalFramerate); - camera_attr_get_preview_fps(self->camera_, ¤t_fps); - - LOG(INFO) << __FUNCTION__ - << " width:" << frame->width - << " height:" << frame->height - << " format:" << toString(frame->format); - -#if defined(OS_TIZEN_MOBILE) - int orientation = EWebView::GetOrientation(); -#else - int orientation = 0; -#endif - int length = frame->data.triple_plane.y_size + - frame->data.triple_plane.u_size + frame->data.triple_plane.v_size; - - LOG(INFO) << __FUNCTION__ << " orientation:" << orientation; - -#if defined(WEBRTC_DEBUG_DUMPFILE) - int written = write(fd, frame->data.triple_plane.y, length); - LOG(INFO) << __FUNCTION__ << " " << written << " bytes written to dump file"; -#endif - - VideoCaptureFormat capture_format_; - capture_format_.frame_size.SetSize(frame->width, frame->height); - capture_format_.frame_rate = current_fps; - capture_format_.pixel_format = PIXEL_FORMAT_I420; - self->client_->OnIncomingCapturedData( - reinterpret_cast(frame->data.triple_plane.y), - length, - capture_format_, - orientation + 90, - base::TimeTicks::Now()); -} - -void VideoCaptureDeviceTizen::OnAllocateAndStart(int width, - int height, - int frame_rate, - VideoPixelFormat format, - scoped_ptr client) { - LOG(INFO) << __FUNCTION__ - << " width:" << width - << " height:" << height - << " frame_rate:" << frame_rate - << " format:" << VideoCaptureFormat::PixelFormatToString(format); - - DCHECK_EQ(worker_.message_loop(), base::MessageLoop::current()); - - client_ = client.Pass(); - int status = CAMERA_ERROR_NONE; - - if (CAMERA_ERROR_NONE != - camera_create(DeviceNameToCameraId(device_name_), &camera_)) { - LOG(ERROR) << "Fail to create camera"; - SetErrorState("Fail to create camera"); - return; - } - - // TODO(max): camera rotation is not working in this moment. - // Need to check after CAPI's investigation. -// if (CAMERA_ERROR_NONE != -// (status = camera_attr_set_stream_rotation(camera_, CAMERA_ROTATION_90))) { -// LOG(WARNING) << " Fail to rotate camera to" << CAMERA_ROTATION_90 -// << " camera_error_e:" << status; -// SetErrorState("Camera internal Error"); -// } - - if (CAMERA_ERROR_NONE != - camera_set_display(camera_, CAMERA_DISPLAY_TYPE_NONE, NULL)) { - LOG(ERROR) << "Fail to set using camera buffer"; - SetErrorState("Camera internal Error"); - return; - } - - if (CAMERA_ERROR_NONE != - camera_set_preview_resolution(camera_, width, height)) { - LOG(WARNING) << "trying default resolution: " - << kMjpegWidth << " x " << kMjpegHeight; - - if (CAMERA_ERROR_NONE != - camera_set_preview_resolution(camera_, kMjpegWidth, kMjpegHeight)) { - LOG(ERROR) << "fail to try default resolution: " - << kMjpegWidth << " x " << kMjpegHeight; - SetErrorState("Camera internal Error"); - return; - } - } - - if (CAMERA_ERROR_NONE != - camera_set_preview_format(camera_, toCapiType(format))) { - std::vector supported_formats; - if (CAMERA_ERROR_NONE != - camera_foreach_supported_preview_format( - camera_, OnPreviewFormat, &supported_formats)) { - LOG(ERROR) << "Cannot get the supported formats for camera"; - SetErrorState("Camera internal Error"); - return; - } - if (supported_formats.empty()) { - LOG(ERROR) << "Cannot get the supported formats for camera"; - SetErrorState("Camera internal Error"); - return; - } - if (CAMERA_ERROR_NONE != - camera_set_preview_format(camera_, supported_formats[0])) { - LOG(ERROR) << "fail to set preview format: " << supported_formats[0]; - SetErrorState("Camera internal Error"); - return; - } - } - - if (CAMERA_ERROR_NONE != - camera_set_preview_cb(camera_, OnCameraCaptured, this)) { - SetErrorState("Camera internal Error"); - return; - } - - if (CAMERA_ERROR_NONE != - camera_attr_set_preview_fps( - camera_, static_cast(frame_rate))) { - LOG(WARNING) << "Camera does not support frame rate:" << frame_rate; - LOG(WARNING) << "trying default frame rate: " << kTypicalFramerate; - if (CAMERA_ERROR_NONE != - camera_attr_set_preview_fps( - camera_, static_cast(kTypicalFramerate))) { - SetErrorState("Camera internal Error"); - return; - } - } - - state_ = kCapturing; - - if (CAMERA_ERROR_NONE != camera_start_preview(camera_)) { - LOG(ERROR) << "Fail to start camera"; - SetErrorState("Camera internal Error"); - } -} - -void VideoCaptureDeviceTizen::OnStopAndDeAllocate() { - DCHECK_EQ(worker_.message_loop(), base::MessageLoop::current()); - - camera_stop_preview(camera_); - camera_destroy(camera_); - DeAllocateVideoBuffers(); - - state_ = kIdle; - client_.reset(); -} - -// TODO(max): Need to find a way how to avoid memcpy by introducing shm holding. -bool VideoCaptureDeviceTizen::AllocateVideoBuffers(int width, int height) { - /* Nothing to do */ - return true; -} - -void VideoCaptureDeviceTizen::DeAllocateVideoBuffers() { - /* Nothing to do */ -} - -void VideoCaptureDeviceTizen::SetErrorState(const std::string& reason) { - DCHECK(!worker_.IsRunning() || - worker_.message_loop() == base::MessageLoop::current()); - state_ = kError; - client_->OnError(reason); -} - -} // namespace media diff --git a/tizen_src/impl/media/video/capture/tizen/video_capture_device_tizen.h b/tizen_src/impl/media/video/capture/tizen/video_capture_device_tizen.h deleted file mode 100644 index b910505a1d79..000000000000 --- a/tizen_src/impl/media/video/capture/tizen/video_capture_device_tizen.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2012 The Samsung Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Tizen specific implementation of VideoCaptureDevice. -// Tizen Core API is used to capture the video frames from the device. - -#ifndef MEDIA_VIDEO_CAPTURE_TIZEN_VIDEO_CAPTURE_DEVICE_TIZEN_H_ -#define MEDIA_VIDEO_CAPTURE_TIZEN_VIDEO_CAPTURE_DEVICE_TIZEN_H_ - -#include - -#include "base/threading/thread.h" -#include "media/video/capture/video_capture_device.h" - -namespace media { - -class VideoCaptureDeviceTizen : public VideoCaptureDevice { - public: - const static std::string kFrontCameraName; - const static std::string kBackCameraName; - const static std::string kFrontCameraId; - const static std::string kBackCameraId; - - explicit VideoCaptureDeviceTizen(const Name& device_name); - virtual ~VideoCaptureDeviceTizen() override; - - virtual void AllocateAndStart(const VideoCaptureParams& params, - scoped_ptr client) override; - - virtual void StopAndDeAllocate() override; - - static camera_device_e DeviceNameToCameraId( - const VideoCaptureDevice::Name& device_name); - - private: - enum InternalState { - kIdle, // The device driver is opened but camera is not in use. - kCapturing, // Video is being captured. - kError // Error accessing HW functions. - // User needs to recover by destroying the object. - }; - - static void OnCameraCaptured(camera_preview_data_s* frame, void* data); - void OnAllocateAndStart(int width, - int height, - int frame_rate, - VideoPixelFormat format, - scoped_ptr client); - void OnStopAndDeAllocate(); - - bool AllocateVideoBuffers(int width, int height); - void DeAllocateVideoBuffers(); - void SetErrorState(const std::string& reason); - - InternalState state_; - scoped_ptr client_; - Name device_name_; - base::Thread worker_; // Thread used for reading data from the device. - scoped_refptr buffer_; - camera_h camera_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(VideoCaptureDeviceTizen); -}; - -} // namespace media - -#endif // MEDIA_VIDEO_CAPTURE_TIZEN_VIDEO_CAPTURE_DEVICE_TIZEN_H_ diff --git a/tizen_src/impl/navigation_policy_params.h b/tizen_src/impl/navigation_policy_params.h deleted file mode 100644 index d35be989cab6..000000000000 --- a/tizen_src/impl/navigation_policy_params.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2014 Samsung Electronics. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef POLICY_NAVIGATION_PARAMS_H_ -#define POLICY_NAVIGATION_PARAMS_H_ - -#include "content/public/common/referrer.h" -#include "third_party/WebKit/public/web/WebNavigationPolicy.h" -#include "third_party/WebKit/public/web/WebNavigationType.h" -#include "third_party/WebKit/public/platform/WebString.h" -#include "url/gurl.h" - -struct NavigationPolicyParams { - int render_view_id; - GURL url; - std::string httpMethod; - content::Referrer referrer; - blink::WebNavigationPolicy policy; - blink::WebNavigationType type; - blink::WebString auth; - std::string cookie; - bool should_replace_current_entry; - bool is_main_frame; - bool is_redirect; -}; - -#endif /* POLICY_NAVIGATION_PARAMS_H_ */ diff --git a/tizen_src/impl/renderer/print_pages_params.cc b/tizen_src/impl/renderer/print_pages_params.cc deleted file mode 100644 index 5e768e21af37..000000000000 --- a/tizen_src/impl/renderer/print_pages_params.cc +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2014 Samsung Electronics. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "renderer/print_pages_params.h" - -PrintParams::PrintParams() - : page_size(), - content_size(), - printable_area(), - dpi(0), - desired_dpi(0), - is_first_request(true), - print_to_pdf(true), - print_scaling_option(blink::WebPrintScalingOptionSourceSize), - document_cookie(0) { -} - -PrintPagesParams::PrintPagesParams() - : pages() { -} diff --git a/tizen_src/impl/renderer/print_pages_params.h b/tizen_src/impl/renderer/print_pages_params.h deleted file mode 100644 index a5cef1f075e9..000000000000 --- a/tizen_src/impl/renderer/print_pages_params.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2014 Samsung Electronics. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef PRINT_PAGES_PARAMS_H_ -#define PRINT_PAGES_PARAMS_H_ - -#include - -#include "base/basictypes.h" -#include "base/files/file_path.h" -#include "base/memory/shared_memory.h" -#include "printing/printing_export.h" -#include "third_party/WebKit/public/web/WebPrintScalingOption.h" -#include "ui/gfx/rect.h" -#include "ui/gfx/size.h" - -struct PrintParams { - PrintParams(); - - gfx::Size page_size; - gfx::Size content_size; - gfx::Rect printable_area; - double dpi; - int desired_dpi; - bool is_first_request; - bool print_to_pdf; - blink::WebPrintScalingOption print_scaling_option; - int document_cookie; -}; - -// collection of printable pages -struct PrintPagesParams { - PrintPagesParams(); - - PrintParams params; - std::vector pages; -}; - -// single page -struct PrintPageParams { - PrintParams params; - int page_number; -}; - -struct DidPrintPagesParams { - base::SharedMemoryHandle metafile_data_handle; - uint32 data_size; - int document_cookie; - base::FilePath filename; -}; - -#endif // PRINT_PAGES_PARAMS_H_ diff --git a/tizen_src/impl/wrt/wrt_url_parse.h b/tizen_src/impl/wrt/wrt_url_parse.h deleted file mode 100644 index a695ea9c7151..000000000000 --- a/tizen_src/impl/wrt/wrt_url_parse.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2014 Samsung Electronics. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef WRT_URL_PARSE_H -#define WRT_URL_PARSE_H - -#include "url/gurl.h" - -namespace content { - -class WrtUrlParseBase { - public: - virtual GURL parseUrl(const GURL& url) const = 0; -}; - -} // namespace content - -#endif // WRT_URL_PARSE_H \ No newline at end of file diff --git a/tizen_src/supplement.gypi b/tizen_src/supplement.gypi index 563e27a666ad..7de3d1f683b9 100644 --- a/tizen_src/supplement.gypi +++ b/tizen_src/supplement.gypi @@ -10,6 +10,8 @@ 'building_for_tizen%': 0, 'building_for_tizen_mobile%': 0, 'building_for_tizen_tv%': 0, + 'tizen_multimedia_support%': 1, + 'tizen_multimedia_use_capi_for_me%': 0, 'data_dir%' : '/usr/share/chromium-efl/', 'exe_dir%' : '/usr/lib/chromium-efl/', @@ -37,7 +39,20 @@ ], 'target_defaults': { + + 'include_dirs': [ + '.', + # Mobile gcc 4.6.x hack begin + '<(DEPTH)/tizen_src/gcc46_compat_wrappers', + # Mobile gcc 4.6.x hack end + ], + + 'defines': [ + 'EWK_BRINGUP=1', + ], + 'conditions': [ + ['use_efl==1', { 'defines': [ 'USE_EFL=1', @@ -46,6 +61,7 @@ '<(DEPTH)/tizen_src/chromium_impl', ], }], + # Mobile gcc 4.6.x hack begin ['gcc_4_6_x==1', { 'defines': [ @@ -56,11 +72,13 @@ 'cflags_cc': [ '-std=gnu++0x', '-fpermissive' ], }], # Mobile gcc 4.6.x hack end + ['prebuilt_ld_gold_dir!=""', { 'ldflags': [ '-B<(prebuilt_ld_gold_dir)', ] }], + ['gcc_version >= 49', { 'ldflags': [ # In GCC 4.9, the linker (either bfd or gold) is called with the -plugin argument @@ -72,6 +90,13 @@ '-fno-use-linker-plugin', ], }], + + ['tizen_multimedia_support==1', { + 'defines': [ + 'TIZEN_MULTIMEDIA_SUPPORT=1', + ], + }], + ['building_for_tizen==1', { 'defines': [ 'OS_TIZEN=1', @@ -103,6 +128,7 @@ }], ], }], + ['building_for_tizen_mobile==1', { 'defines': [ 'OS_TIZEN_MOBILE=1', @@ -110,18 +136,22 @@ 'TIZEN_ENABLE_CAPI_SUPPORT=1', ], }], + ['building_for_tizen_tv==1', { 'defines': [ 'OS_TIZEN_TV=1', ], + 'conditions': [ + ['chromium_efl_tizen_version=="2.2.1"', { + 'defines': [ + 'TIZEN_MULTIMEDIA_PIXMAP_SUPPORT=1', + ], + }], + ], }], - ], - 'include_dirs': [ - '.', - # Mobile gcc 4.6.x hack begin - '<(DEPTH)/tizen_src/gcc46_compat_wrappers', - # Mobile gcc 4.6.x hack end - ], + + ], # conditions + # Mobile gcc 4.6.x hack begin 'target_conditions': [ ['_target_name=="boringssl" or _target_name=="crypto" or _target_name=="genperf" or _target_name=="yasm" or _target_name=="speech_proto" or _target_name=="skia_library" or _target_name=="http_server" or _target_name=="libjingle" or _target_name=="libjingle_webrtc_common" or _target_name=="content_renderer" or _target_name=="mesa_libglslcommon"', { @@ -142,5 +172,6 @@ }], ], # Mobile gcc 4.6.x hack end - }, #target_defaults + + }, # target_defaults }