1 // Copyright 2014 Samsung Electronics Inc. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/common/gpu/media/tizen/tizen_video_decode_accelerator.h"
7 #include <gst/app/gstappsink.h>
8 #include <gst/app/gstappsrc.h>
10 #include <gst/video/gstvideosink.h>
11 #include <gst/video/video.h>
13 #include "base/bind.h"
14 #include "base/memory/shared_memory.h"
15 #include "base/message_loop/message_loop_proxy.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "base/time/time.h"
18 #if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
19 #include "ui/gl/efl_pixmap.h"
21 #include "base/process/process.h"
24 #if GST_VERSION_MAJOR == 1
25 #include <gst/video/videooverlay.h>
27 #include <gst/interfaces/xoverlay.h>
30 using media::VideoFrame;
34 struct GstElementDeleter {
35 void operator()(GstElement* ptr) const {
37 gst_object_unref(ptr);
41 // Gstreamer elements and names.
42 const char* kDecoderName = "decoder";
43 #if GST_VERSION_MAJOR == 1
44 const char* kDecoderGstElement = "omxh264dec";
46 const char* kDecoderGstElement = "omx_h264dec";
49 // Generating Unique Key from given width and height.
50 int32 ConvertWidthAndHeightToKey(int width, int height) {
51 return ((width << 16) | height);
58 MAX_BITRATE = 2000000, // bps.
59 INPUT_BUFFER_SIZE = MAX_BITRATE / 8, // bytes. 1 sec for H.264 HD video.
60 ID_LAST = 0x3FFFFFFF, // wrap round ID after this
63 media::VideoDecodeAccelerator* CreateTizenVideoDecodeAccelerator() {
64 return new TizenVideoDecodeAccelerator();
67 struct TizenVideoDecodeAccelerator::BitstreamBufferRef {
69 base::WeakPtr<media::VideoDecodeAccelerator::Client> client,
70 const scoped_refptr<base::MessageLoopProxy>& client_message_loop_proxy,
71 base::SharedMemory* shm,
75 client_message_loop_proxy_(client_message_loop_proxy),
82 ~BitstreamBufferRef() {
84 client_message_loop_proxy_->PostTask(
87 &media::VideoDecodeAccelerator::Client::NotifyEndOfBitstreamBuffer,
93 static void Destruct(gpointer data) {
95 BitstreamBufferRef* pRef = static_cast<BitstreamBufferRef*>(data);
99 base::WeakPtr<media::VideoDecodeAccelerator::Client> client_;
100 scoped_refptr<base::MessageLoopProxy> client_message_loop_proxy_;
101 scoped_ptr<base::SharedMemory> shm_;
105 GstBuffer* gst_buffer_;
108 struct TizenVideoDecodeAccelerator::Impl {
111 is_destroying_(false),
115 io_message_loop_proxy_(base::MessageLoopProxy::current()),
116 bitstream_buffer_id_(0),
117 gst_thread_("TizenDecoderThreadGst")
118 #if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
123 damage_handler_(NULL),
124 is_x_window_handle_set_(false)
130 #if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
131 xpixmap_buffer_map_.clear();
135 #if !defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
136 static GstFlowReturn OnDecoded(GstAppSink* sink, gpointer app_data);
137 void DeliverVideoFrame(GstBuffer* buffer,
138 int32 bitstream_buffer_id,
139 gfx::Rect frame_size);
140 void CreateAppSinkElement();
141 static void OnSinkCapChanged(
142 GstPad* sink_pad, GParamSpec* gparamspec, void* user_data);
145 static GstBusSyncReply OnBusMessage(
146 GstBus* bus, GstMessage* msg, gpointer data) {
147 switch (GST_MESSAGE_TYPE(msg)) {
148 case GST_MESSAGE_ERROR: {
150 GError* error = NULL;
151 gst_message_parse_error(msg, &error, &debug);
152 LOG(ERROR) << __FUNCTION__
153 << " GSTError happens from bus at "
154 << GST_OBJECT_NAME(msg->src)
155 << ":" << error->message;
156 LOG(ERROR) << __FUNCTION__
157 << " Debugging Info: "
158 << (debug != NULL ? debug : "none");
163 #if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
164 case GST_MESSAGE_ELEMENT: {
165 TizenVideoDecodeAccelerator::Impl* obj_impl =
166 static_cast<TizenVideoDecodeAccelerator::Impl*>(data);
168 if (obj_impl->IsXWindowHandleSet()) {
169 #if GST_VERSION_MAJOR == 1
170 if (gst_is_video_overlay_prepare_window_handle_message(msg)) {
172 if (gst_structure_has_name(msg->structure, "prepare-xid")) {
174 obj_impl->OnXWindowIdPrepared(msg);
175 gst_message_unref(msg);
180 LOG(ERROR) << __FUNCTION__ << "Accelerator is NULL";
191 static void StartFeed(GstAppSrc *source, guint size, gpointer app) {
193 content::TizenVideoDecodeAccelerator::Impl* impl =
194 static_cast<content::TizenVideoDecodeAccelerator::Impl*>(app);
195 impl->can_feed_ = true;
198 static void StopFeed(GstAppSrc *source, gpointer app) {
200 content::TizenVideoDecodeAccelerator::Impl* impl =
201 static_cast<content::TizenVideoDecodeAccelerator::Impl*>(app);
202 impl->can_feed_ = false;
205 #if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
206 bool IsXWindowHandleSet() const {return is_x_window_handle_set_;}
207 void OnXWindowIdPrepared(GstMessage* message);
208 void SetXWindowHandle(bool handle_set);
209 void SetPixmap(const int32& gst_width, const int32& gst_height);
210 void DeregisterDamageHandler();
211 static Eina_Bool OnSurfaceChanged(void* ptr_acc, int type, void* event);
212 static void OnSinkCapChanged(
213 GstPad* sink_pad, GParamSpec* gparamspec, void* user_data);
216 volatile bool can_feed_;
217 volatile bool is_destroying_;
218 GstElement* pipeline_;
221 scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
222 scoped_ptr<base::WeakPtrFactory<Client> > io_client_weak_factory_;
223 base::Thread gst_thread_;
224 int bitstream_buffer_id_;
225 #if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
226 scoped_refptr<gfx::EflPixmap> pixmap_surface_;
230 Ecore_X_Damage damage_;
231 Ecore_Event_Handler* damage_handler_;
232 bool is_x_window_handle_set_;
233 typedef std::map<int16, scoped_refptr<gfx::EflPixmap> > PixmapSurfaceTizenMap;
234 PixmapSurfaceTizenMap xpixmap_buffer_map_;
241 TizenVideoDecodeAccelerator::TizenVideoDecodeAccelerator()
245 TizenVideoDecodeAccelerator::~TizenVideoDecodeAccelerator() {
248 bool TizenVideoDecodeAccelerator::Initialize(
249 media::VideoCodecProfile profile,
251 GError* error = NULL;
252 GstCaps* video_caps = NULL;
253 GstElement* gst_decoder = NULL;
254 GstElement* gst_parser = NULL;
255 GstBus* gst_bus = NULL;
256 GstPad* video_sink_pad = NULL;
257 #if !defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
258 GstElement* video_filter_ = NULL;
259 GstElement* gst_converter = NULL;
261 scoped_ptr<GstElement, GstElementDeleter> gst_pipeline;
262 static GstAppSrcCallbacks appsrc_callbacks =
263 {&Impl::StartFeed, &Impl::StopFeed, NULL};
264 CHECK(impl_ == NULL);
266 impl_->io_client_weak_factory_.reset(
267 new base::WeakPtrFactory<Client>(client));
270 case media::H264PROFILE_BASELINE:
271 DVLOG(1) << "Initialize(): profile -> H264PROFILE_BASELINE";
273 case media::H264PROFILE_MAIN:
274 DVLOG(1) << "Initialize(): profile -> H264PROFILE_MAIN";
277 LOG(ERROR) << "Initialize(): unsupported profile=" << profile;
281 if (!gst_is_initialized() && !gst_init_check(NULL, NULL, &error)) {
282 LOG(ERROR) << __FUNCTION__ << "cannot initialize gstreamer.";
287 // pipeline initialization.
288 gst_pipeline.reset(gst_pipeline_new("h264_decode"));
290 LOG(ERROR) << __FUNCTION__ << "cannot initialize gst pipeline.";
293 if (!(gst_bus = gst_pipeline_get_bus(GST_PIPELINE(gst_pipeline.get())))) {
296 #if GST_VERSION_MAJOR == 1
297 gst_bus_set_sync_handler(gst_bus, Impl::OnBusMessage, impl_, NULL);
299 gst_bus_set_sync_handler(gst_bus, Impl::OnBusMessage, impl_);
301 gst_object_unref(gst_bus);
303 // appsrc initialization.
304 if (!(impl_->appsrc_ = gst_element_factory_make("appsrc", "src"))) {
305 LOG(ERROR) << __FUNCTION__ << "cannot initialize gst appsrc.";
308 if (!gst_bin_add(GST_BIN(gst_pipeline.get()), impl_->appsrc_)) {
309 gst_object_unref(impl_->appsrc_);
310 impl_->appsrc_ = NULL;
313 gst_app_src_set_max_bytes(GST_APP_SRC(impl_->appsrc_), INPUT_BUFFER_SIZE);
314 gst_app_src_set_callbacks(GST_APP_SRC(impl_->appsrc_), &appsrc_callbacks,
315 static_cast<gpointer>(impl_), NULL);
316 g_object_set(G_OBJECT(impl_->appsrc_),
319 "min-percent", 80, // if buffer below 80%, need-data emits.
320 "stream-type", GST_APP_STREAM_TYPE_STREAM,
322 if (!(video_caps = gst_caps_from_string("video/x-h264,framerate=30/1"))) {
325 gst_app_src_set_caps(GST_APP_SRC(impl_->appsrc_), video_caps);
326 gst_caps_unref(video_caps);
328 #if defined(OS_TIZEN)
329 DVLOG(1) << "######################################";
330 DVLOG(1) << " USING omx_h264dec DECODER " << (unsigned int)this;
331 DVLOG(1) << "######################################";
333 // parser initialization
334 if (!(gst_parser = gst_element_factory_make("h264parse", "h264parse"))) {
335 LOG(ERROR) << " cannot create h264parse.";
338 if(!gst_bin_add(GST_BIN(gst_pipeline.get()), gst_parser)) {
339 LOG(ERROR) << " cannot add h264parse into decoder pipeline.";
340 gst_object_unref(gst_parser);
344 // decoder initialization.
345 if (!(gst_decoder = gst_element_factory_make(kDecoderGstElement, kDecoderName))) {
346 LOG(ERROR) << " cannot create " << kDecoderGstElement << ".";
349 if (!gst_bin_add(GST_BIN(gst_pipeline.get()), gst_decoder)) {
350 LOG(ERROR) << " cannot add " << kDecoderGstElement << " to pipeline.";
351 gst_object_unref(gst_decoder);
354 #if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
355 // sink initialization.
356 if (!(impl_->sink_ = gst_element_factory_make("xvimagesink", "xvimagesink"))) {
357 LOG(ERROR) << __FUNCTION__ << " cannot create xvimagesink.";
360 if (!gst_bin_add(GST_BIN(gst_pipeline.get()), impl_->sink_)) {
361 gst_object_unref(impl_->sink_);
365 g_object_set(impl_->sink_, "rotate", 0, NULL);
367 if (!(video_sink_pad = gst_element_get_static_pad(impl_->sink_, "sink"))) {
370 g_signal_connect(video_sink_pad, "notify::caps",
371 G_CALLBACK(impl_->OnSinkCapChanged),
373 impl_->SetXWindowHandle(false);
374 gst_object_unref(video_sink_pad);
376 // linking the elements.
377 if (!gst_element_link(impl_->appsrc_, gst_parser)) {
378 LOG(ERROR) << " Source and gst_parser could not be linked";
382 if (!gst_element_link(gst_parser, gst_decoder)) {
383 LOG(ERROR) << " gst_parser and Decoder could not be linked";
386 if (!gst_element_link(gst_decoder, impl_->sink_)) {
387 LOG(ERROR) << __FUNCTION__ << " Decoder and Sink could not be linked";
391 impl_->CreateAppSinkElement();
393 LOG(ERROR) << "Could not create and add appsink element";
396 if (!gst_bin_add(GST_BIN(gst_pipeline.get()), impl_->sink_)) {
397 gst_object_unref(impl_->sink_);
401 if (!(gst_converter = gst_element_factory_make("fimcconvert", "cvt"))) {
402 LOG(ERROR) << __FUNCTION__ << " cannot create fimcconvert.";
405 if(!gst_bin_add(GST_BIN(gst_pipeline.get()), gst_converter)) {
406 LOG(ERROR) << __FUNCTION__ << " cannot add fimcconvert into pipeline.";
407 gst_object_unref(gst_converter);
410 if (!(video_filter_ = gst_element_factory_make("capsfilter", "VideoFilter"))) {
411 LOG(ERROR) << __FUNCTION__ << " cannot create capsfilter.";
414 if(!gst_bin_add(GST_BIN(gst_pipeline.get()), video_filter_)) {
415 LOG(ERROR) << __FUNCTION__ << " cannot add videoFilter into pipeline.";
416 gst_object_unref(video_filter_);
421 // OnSinkCapChanged callback is not coming for Appsink implementation
422 if (!(video_sink_pad =
423 gst_element_get_static_pad(impl_->sink_, "sink"))) {
424 LOG(ERROR) << "Could not create video sink pad";
428 video_sink_pad, "notify::caps",
429 G_CALLBACK(&Impl::OnSinkCapChanged), impl_);
430 gst_object_unref(video_sink_pad);
431 if (!gst_element_link_many(impl_->appsrc_,
438 LOG(ERROR) << __FUNCTION__ << " cannot link some elements in decode pipeline";
441 g_object_set(G_OBJECT(video_filter_),
443 gst_caps_new_simple("video/x-raw","format", G_TYPE_STRING, "I420",NULL),
447 DVLOG(1) << "######################################";
448 DVLOG(1) << " USING ffdec_h264 DECODER";
449 DVLOG(1) << "######################################";
450 GstElement* gst_colorspace = NULL;
452 // decoder initialization
453 if (!(gst_decoder = gst_element_factory_make("ffdec_h264", "H264-decoder"))) {
454 LOG(ERROR) << __FUNCTION__ << " cannot create ffdec_h264.";
457 if (!gst_bin_add(GST_BIN(gst_pipeline.get()), gst_decoder)) {
458 gst_object_unref(gst_decoder);
462 // colorspace initialization
463 if (!(gst_colorspace = gst_element_factory_make("ffmpegcolorspace", "cs"))) {
464 LOG(ERROR) << __FUNCTION__ << " cannot create ffmpegcolorspace.";
467 if (!gst_bin_add(GST_BIN(gst_pipeline.get()), gst_colorspace)) {
468 gst_object_unref(gst_colorspace);
472 if (!(impl_->sink_ = gst_element_factory_make("autovideosink", "sink"))) {
473 LOG(ERROR) << __FUNCTION__ << " cannot create autovideosink.";
476 if (!gst_bin_add(GST_BIN(gst_pipeline.get()), impl_->sink_)) {
477 gst_object_unref(impl_->sink_);
482 if(!gst_element_link_many(impl_->appsrc_, gst_decoder, gst_colorspace,
483 impl_->sink_, NULL)) {
484 LOG(ERROR) << __FUNCTION__ << " Some element could not be linked";
488 if (!impl_->gst_thread_.Start()) {
489 LOG(ERROR) << __FUNCTION__ << " gst_thread_ failed to start";
493 impl_->gst_thread_.message_loop()->PostTask(
495 base::Bind(&TizenVideoDecodeAccelerator::StartDecoder,
496 base::Unretained(this)));
498 GST_DEBUG_BIN_TO_DOT_FILE(
499 GST_BIN(gst_pipeline.get()), GST_DEBUG_GRAPH_SHOW_ALL, "decoder_graph.dot");
501 impl_->pipeline_ = gst_pipeline.release();
505 void TizenVideoDecodeAccelerator::Decode(
506 const media::BitstreamBuffer& bitstream_buffer) {
507 scoped_ptr<BitstreamBufferRef> buffer_ref;
508 scoped_ptr<base::SharedMemory> shm(
509 new base::SharedMemory(bitstream_buffer.handle(), true));
511 if (!shm->Map(bitstream_buffer.size())) {
512 LOG(ERROR) << __FUNCTION__ << " could not map bitstream_buffer";
513 NotifyError(media::VideoDecodeAccelerator::UNREADABLE_INPUT);
517 buffer_ref.reset(new BitstreamBufferRef(
518 impl_->io_client_weak_factory_->GetWeakPtr(),
519 base::MessageLoopProxy::current(),
521 bitstream_buffer.size(),
522 bitstream_buffer.id()));
528 if (impl_->can_feed_ && !impl_->is_destroying_) {
529 impl_->gst_thread_.message_loop()->PostTask(
531 base::Bind(&TizenVideoDecodeAccelerator::OnDecode,
532 base::Unretained(this),
533 base::Passed(&buffer_ref)));
535 DVLOG(2) << __FUNCTION__
536 << " Frame drop on decoder:"
537 << " INPUT Q is FULL";
541 void TizenVideoDecodeAccelerator::AssignPictureBuffers(
542 const std::vector<media::PictureBuffer>& buffers) {
546 void TizenVideoDecodeAccelerator::ReusePictureBuffer(
547 int32 picture_buffer_id) {
551 void TizenVideoDecodeAccelerator::Flush() {
555 void TizenVideoDecodeAccelerator::Reset() {
559 void TizenVideoDecodeAccelerator::Destroy() {
561 #if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
562 impl_->SetXWindowHandle(false);
563 impl_->DeregisterDamageHandler();
564 impl_->xpixmap_buffer_map_.clear();
566 if (impl_->gst_thread_.IsRunning()) {
567 impl_->gst_thread_.Stop();
569 gst_app_src_end_of_stream(GST_APP_SRC(impl_->appsrc_));
570 impl_->is_destroying_ = true;
571 if (impl_->pipeline_) {
572 gst_element_set_state(impl_->pipeline_, GST_STATE_NULL);
573 gst_object_unref(GST_OBJECT(impl_->pipeline_));
581 bool TizenVideoDecodeAccelerator::CanDecodeOnIOThread(){
585 void TizenVideoDecodeAccelerator::StartDecoder() {
586 gst_element_set_state(impl_->pipeline_, GST_STATE_PLAYING);
589 #if !defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
590 void TizenVideoDecodeAccelerator::Impl::OnSinkCapChanged(
591 GstPad* sink_pad, GParamSpec* gparamspec, void* user_data) {
592 content::TizenVideoDecodeAccelerator::Impl* impl =
593 static_cast<TizenVideoDecodeAccelerator::Impl*>(user_data);
594 int width = 0, height = 0;
595 #if GST_VERSION_MAJOR == 1
596 GstCaps* caps = gst_pad_get_current_caps(GST_PAD(sink_pad));
599 gst_video_info_init(&info);
600 if (gst_video_info_from_caps(&info, caps)) {
601 if ((impl->caps_width_ != width) || (impl->caps_height_ != height)) {
602 impl->caps_width_ = info.width;
603 impl->caps_height_ = info.height;
608 if (gst_video_get_size(sink_pad, &width, &height)) {
609 if ((impl->caps_width_ != width) || (impl->caps_height_ != height)) {
610 impl->caps_width_ = width;
611 impl->caps_height_ = height;
617 GstFlowReturn TizenVideoDecodeAccelerator::Impl::OnDecoded(
618 GstAppSink* sink, gpointer app_data) {
619 GstBuffer* gst_output_buf = NULL;
620 content::TizenVideoDecodeAccelerator::Impl* self =
621 static_cast<TizenVideoDecodeAccelerator::Impl*>(app_data);
623 // Once OnSinkCapChanged callback startes coming dont find height
624 // and width for all buffers, move this code under if block
625 #if GST_VERSION_MAJOR == 1
626 GstSample* sample = gst_app_sink_pull_sample(GST_APP_SINK(sink));
627 gst_output_buf = gst_sample_get_buffer(sample);
629 if (!gst_buffer_map(gst_output_buf, &map, GST_MAP_READ))
630 LOG (ERROR) << "Decoded Buffer contains invalid or no info!";
631 GstCaps* caps = gst_sample_get_caps(sample);
633 gst_output_buf = gst_app_sink_pull_buffer(GST_APP_SINK(sink));
634 GstCaps* caps = gst_buffer_get_caps(GST_BUFFER(gst_output_buf));
636 if (!self->caps_width_ || !self->caps_height_) {
638 LOG(ERROR) << __FUNCTION__ << "Could not fetch caps from buffer";
639 gst_buffer_unref(gst_output_buf);
640 return GST_FLOW_ERROR;
642 // No need to unref |GstStructure|
643 const GstStructure* str = gst_caps_get_structure(caps, 0);
645 gst_buffer_unref(gst_output_buf);
646 gst_caps_unref(caps);
647 return GST_FLOW_ERROR;
649 if (!gst_structure_get_int(str, "width", &self->caps_width_) ||
650 !gst_structure_get_int(str, "height", &self->caps_height_)) {
651 LOG(ERROR) << "Buffer information could not be obtained";
652 gst_buffer_unref(gst_output_buf);
653 gst_caps_unref(caps);
654 return GST_FLOW_ERROR;
656 gst_caps_unref(caps);
660 if (gst_output_buf) {
661 #if GST_VERSION_MAJOR == 1
664 if (gst_output_buf->data) {
666 gfx::Rect frame_size =
667 gfx::Rect(self->caps_width_, self->caps_height_);
668 self->gst_thread_.message_loop()->PostTask(
670 base::Bind(&TizenVideoDecodeAccelerator::Impl::DeliverVideoFrame,
671 base::Unretained(self),
673 self->bitstream_buffer_id_,
675 self->bitstream_buffer_id_ = (self->bitstream_buffer_id_ + 1) & ID_LAST;
678 gst_buffer_unref(gst_output_buf);
679 #if GST_VERSION_MAJOR == 1
680 gst_sample_unref(sample);
682 LOG(ERROR) << __FUNCTION__
683 << " DECODING FRAME FAILED : frame_id"
684 << self->bitstream_buffer_id_;
686 #if GST_VERSION_MAJOR == 1
687 gst_buffer_unmap(gst_output_buf, &map);
693 void TizenVideoDecodeAccelerator::Impl::CreateAppSinkElement() {
694 GstAppSinkCallbacks appsink_callbacks =
695 {NULL, NULL, &OnDecoded, NULL};
697 if (!(sink_ = gst_element_factory_make("appsink", "sink"))) {
698 LOG(ERROR) << __FUNCTION__ << "Appsink could not be created";
701 gst_app_sink_set_callbacks(GST_APP_SINK(sink_),
703 static_cast<gpointer>(this),
705 gst_app_sink_set_max_buffers(GST_APP_SINK(sink_), 1);
708 void TizenVideoDecodeAccelerator::Impl::DeliverVideoFrame(
710 int32 bitstream_buffer_id,
711 gfx::Rect frame_size) {
712 base::SharedMemory shared_memory;
713 base::SharedMemoryHandle shared_memory_handle;
715 #if GST_VERSION_MAJOR == 1
717 if (!gst_buffer_map(buffer, &map, GST_MAP_READ)) {
718 LOG (ERROR) << "Encoded Buffer contains invalid or no info.!";
721 uint32 buffer_size = map.size;
723 uint32 buffer_size = buffer->size;
725 if (!shared_memory.CreateAndMapAnonymous(buffer_size)) {
726 LOG (ERROR) << "Shared Memory creation failed.";
728 if (!shared_memory.ShareToProcess(base::GetCurrentProcessHandle(),
729 &shared_memory_handle)) {
730 LOG(ERROR) << __FUNCTION__ << "Could not get handle of Shared Memory";
732 memcpy(shared_memory.memory(),
733 #if GST_VERSION_MAJOR == 1
736 GST_BUFFER_DATA(buffer),
739 io_message_loop_proxy_->PostTask(
741 base::Bind(&media::VideoDecodeAccelerator::Client::NotifyDecodeDone,
742 io_client_weak_factory_->GetWeakPtr(),
743 shared_memory_handle,
744 bitstream_buffer_id_,
749 #if GST_VERSION_MAJOR == 1
750 gst_buffer_unmap(buffer, &map);
752 gst_buffer_unref(buffer);
756 #if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
757 void TizenVideoDecodeAccelerator::Impl::OnXWindowIdPrepared(
758 GstMessage* message) {
759 #if GST_VERSION_MAJOR == 1
760 const GstStructure* structure = gst_message_get_structure(message);
761 gst_structure_get_int(structure, "video-width", &gst_width_);
762 gst_structure_get_int(structure, "video-height", &gst_height_);
764 gst_structure_get_int(message->structure, "video-width", &gst_width_);
765 gst_structure_get_int(message->structure, "video-height", &gst_height_);
767 SetPixmap(gst_width_, gst_height_);
768 SetXWindowHandle(true);
771 void TizenVideoDecodeAccelerator::Impl::SetXWindowHandle(
773 is_x_window_handle_set_ = handle_set;
776 void TizenVideoDecodeAccelerator::Impl::SetPixmap(
777 const int32& gst_width, const int32& gst_height) {
778 int32 key_wh = ConvertWidthAndHeightToKey(gst_width, gst_height);
779 PixmapSurfaceTizenMap::iterator it = xpixmap_buffer_map_.find(key_wh);
780 if (it != xpixmap_buffer_map_.end()) {
781 pixmap_surface_ = it->second;
782 pixmap_id_ = pixmap_surface_->GetId();
785 gfx::EflPixmap::Create(gfx::EflPixmapBase::UsageType::SURFACE,
786 gfx::Size(gst_width, gst_height));
787 if (pixmap_surface_.get() == NULL) {
788 LOG(ERROR) << __FUNCTION__ << "Failed to create pixmap Surface";
791 pixmap_id_ = pixmap_surface_->GetId();
792 xpixmap_buffer_map_[key_wh] = pixmap_surface_;
794 gst_width_ = gst_width;
795 gst_height_ = gst_height;
796 DeregisterDamageHandler();
798 // Register to get notification from ecore for damage updates.
799 damage_ = ecore_x_damage_new(pixmap_id_,
800 ECORE_X_DAMAGE_REPORT_RAW_RECTANGLES);
801 damage_handler_ = ecore_event_handler_add(ECORE_X_EVENT_DAMAGE_NOTIFY,
804 #if GST_VERSION_MAJOR == 1
805 gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(sink_), pixmap_id_);
807 gst_x_overlay_set_window_handle(GST_X_OVERLAY(sink_), pixmap_id_);
811 void TizenVideoDecodeAccelerator::Impl::DeregisterDamageHandler() {
813 ecore_x_damage_free(damage_);
816 if (damage_handler_) {
817 ecore_event_handler_del(damage_handler_);
818 damage_handler_ = NULL;
822 // Callback received when pixmap surface is changed/damaged
823 Eina_Bool TizenVideoDecodeAccelerator::Impl::OnSurfaceChanged(void* ptr_acc,
826 TizenVideoDecodeAccelerator::Impl* self =
827 static_cast<TizenVideoDecodeAccelerator::Impl*>(ptr_acc);
830 media::Picture picture(self->pixmap_id_,
831 self->bitstream_buffer_id_,
832 gfx::Rect(self->gst_width_, self->gst_height_));
834 self->io_message_loop_proxy_->PostTask(
836 base::Bind(&media::VideoDecodeAccelerator::Client::PictureReady,
837 self->io_client_weak_factory_->GetWeakPtr(),
839 self->bitstream_buffer_id_ = (self->bitstream_buffer_id_ + 1) & ID_LAST;
841 LOG(ERROR) << __FUNCTION__ << "Accelerator is NULL";
842 return ECORE_CALLBACK_CANCEL;
844 return ECORE_CALLBACK_PASS_ON;
847 void TizenVideoDecodeAccelerator::Impl::OnSinkCapChanged(
848 GstPad* sink_pad, GParamSpec* gparamspec,void* user_data) {
849 TizenVideoDecodeAccelerator::Impl* self =
850 static_cast<TizenVideoDecodeAccelerator::Impl*>(user_data);
852 LOG(ERROR) << __FUNCTION__ << "Accelerator is NULL";
856 int width = 0, height = 0;
857 #if GST_VERSION_MAJOR == 1
858 GstCaps* caps = gst_pad_get_current_caps(GST_PAD(sink_pad));
861 gst_video_info_init(&info);
863 if (gst_video_info_from_caps(&info, caps)) {
865 height = info.height;
866 if ((self->gst_width_ != width) || (self->gst_height_ != height)) {
867 self->SetPixmap(width, height);
872 if (gst_video_get_size(sink_pad, &width, &height)) {
873 if ((self->gst_width_ != width) || (self->gst_height_ != height)) {
874 self->SetPixmap(width, height);
881 void TizenVideoDecodeAccelerator::OnDecode(
882 scoped_ptr<BitstreamBufferRef> buffer_ref) {
886 #if GST_VERSION_MAJOR == 1
887 buffer_ref->gst_buffer_ =
888 gst_buffer_new_wrapped_full(GST_MEMORY_FLAG_READONLY,
889 static_cast<guint8*>(buffer_ref->shm_->memory()),
893 reinterpret_cast<guint8*>(buffer_ref.get()),
894 BitstreamBufferRef::Destruct);
895 if (!buffer_ref->gst_buffer_ || !GST_IS_BUFFER(buffer_ref->gst_buffer_)) {
896 LOG(ERROR) << " gst_buffer_new_wrapped_full failed to allocate memory.!";
900 if (!(buffer_ref->gst_buffer_ = gst_buffer_new())) {
904 GST_BUFFER_MALLOCDATA(buffer_ref->gst_buffer_) =
905 reinterpret_cast<guint8*>(buffer_ref.get());
906 GST_BUFFER_FREE_FUNC(buffer_ref->gst_buffer_) = BitstreamBufferRef::Destruct;
907 GST_BUFFER_SIZE(buffer_ref->gst_buffer_) = buffer_ref->size_;
908 GST_BUFFER_DATA(buffer_ref->gst_buffer_) =
909 static_cast<guint8*>(buffer_ref->shm_->memory());
912 gst_app_src_push_buffer(GST_APP_SRC(impl_->appsrc_),
913 buffer_ref->gst_buffer_)) {
914 LOG(ERROR) << __FUNCTION__ << " fail to push buffer into decoder pipeline";
918 // lifecycle of buffer_ref will be handled by gstreamer.
919 buffer_ref.release();
922 void TizenVideoDecodeAccelerator::NotifyError(
923 media::VideoDecodeAccelerator::Error error) {
924 if (impl_->io_client_weak_factory_->GetWeakPtr()) {
925 impl_->io_client_weak_factory_->GetWeakPtr()->NotifyError(error);
929 } // namespace content