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