#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"
+#endif
#if GST_VERSION_MAJOR == 1
#include <gst/video/videooverlay.h>
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.
+#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
+ ID_LAST = 0x3FFFFFFF, // wrap round ID after this
+#endif
};
media::VideoDecodeAccelerator* CreateTizenVideoDecodeAccelerator() {
sink_(NULL),
appsrc_(NULL),
io_message_loop_proxy_(base::MessageLoopProxy::current()),
- gst_thread_("TizenDecoderThreadGst") {}
+ gst_thread_("TizenDecoderThreadGst")
+#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
+ ,bitstream_buffer_id_(0),
+ pixmap_id_(0),
+ gst_width_(0),
+ gst_height_(0),
+ damage_(0),
+ damage_handler_(NULL),
+ is_x_window_handle_set_(false)
+#endif
+{
+#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
+ xpixmap_buffer_map_.clear();
+#endif
+}
static GstBusSyncReply OnBusMessage(
GstBus* bus, GstMessage* msg, gpointer data) {
g_free(debug);
break;
}
- default: NOTREACHED();
+#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
+ case GST_MESSAGE_ELEMENT: {
+ TizenVideoDecodeAccelerator::Impl* obj_impl =
+ static_cast<TizenVideoDecodeAccelerator::Impl*>(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;
}
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_;
scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
scoped_ptr<base::WeakPtrFactory<Client> > io_client_weak_factory_;
base::Thread gst_thread_;
+#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
+ int bitstream_buffer_id_;
+ scoped_refptr<gfx::EflPixmap> 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<int16, scoped_refptr<gfx::EflPixmap> > PixmapSurfaceTizenMap;
+ PixmapSurfaceTizenMap xpixmap_buffer_map_;
+#endif
};
TizenVideoDecodeAccelerator::TizenVideoDecodeAccelerator()
GstCaps* video_caps = NULL;
GstElement* gst_decoder = NULL;
GstBus* gst_bus = NULL;
+ GstPad* video_sink_pad = NULL;
scoped_ptr<GstElement, GstElementDeleter> gst_pipeline;
static GstAppSrcCallbacks appsrc_callbacks =
{&Impl::StartFeed, &Impl::StopFeed, NULL};
return false;
}
g_object_set(impl_->sink_, "rotate", 0, NULL);
+#if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
+ 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);
+#endif
// linking the elements.
if (!gst_element_link(impl_->appsrc_, gst_decoder)) {
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_element_set_state(impl_->pipeline_, GST_STATE_PLAYING);
};
+#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<TizenVideoDecodeAccelerator::Impl*>(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<TizenVideoDecodeAccelerator::Impl*>(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<BitstreamBufferRef> buffer_ref) {
if (!buffer_ref) {