GstElement* MediaTransporterDisplay::videoSink()
{
std::lock_guard<std::mutex> mutex(_mutex);
-
+ mm_display_type_e displayType = MM_DISPLAY_TYPE_NONE;
try {
+ std::string videoSinkName;
+
switch (_type) {
case MTPR_DISPLAY_TYPE_OVERLAY:
+ displayType = MM_DISPLAY_TYPE_OVERLAY;
+ videoSinkName = MediaTransporterIni::get().renderingSink().videoSinkElement;
LOG_INFO("it's OVERLAY type");
break;
+ case MTPR_DISPLAY_TYPE_EVAS:
+ LOG_INFO("it's EVAS type");
+ displayType = MM_DISPLAY_TYPE_EVAS;
+ videoSinkName = gst::DEFAULT_ELEMENT_FAKESINK;
+ break;
default:
LOG_ERROR_IF_REACHED("type(%d)", _type);
throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "_display is NULL");
- break;
}
- std::string videoSinkName = MediaTransporterIni::get().renderingSink().videoSinkElement;
_sinkElement = gst::_createElement(videoSinkName);
- applyModeProperty();
- applyVisibleProperty();
int overlaySurfaceId = -1;
- if (mm_display_interface_set_display_mainloop_sync(_mmDisplay, MM_DISPLAY_TYPE_OVERLAY, _surface, &overlaySurfaceId) != MM_ERROR_NONE)
+ if (mm_display_interface_set_display_mainloop_sync(_mmDisplay, displayType, _surface, &overlaySurfaceId) != MM_ERROR_NONE)
throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to mm_display_interface_set_display_mainloop_sync()");
+ applyModeProperty();
+ applyVisibleProperty();
+
LOG_INFO("surface[%p], got overlaySurfaceId[%d]", _surface, overlaySurfaceId);
- gst_video_overlay_set_wl_window_wl_surface_id(GST_VIDEO_OVERLAY(_sinkElement), overlaySurfaceId);
+ if (_type == MTPR_DISPLAY_TYPE_OVERLAY)
+ gst_video_overlay_set_wl_window_wl_surface_id(GST_VIDEO_OVERLAY(_sinkElement), overlaySurfaceId);
return GST_ELEMENT(gst_object_ref(_sinkElement));
} catch (const MediaTransporterException& e) {
gst_object_unref(_sinkElement);
_sinkElement = nullptr;
}
-
throw;
}
}
void MediaTransporterDisplay::applyVisibleProperty()
{
- if (g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(_sinkElement)), "visible"))
- g_object_set(G_OBJECT(_sinkElement),
- "visible", _visible, NULL);
+ if (_type == MTPR_DISPLAY_TYPE_OVERLAY) {
+ if (g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(_sinkElement)), "visible"))
+ g_object_set(G_OBJECT(_sinkElement),
+ "visible", _visible, NULL);
+ } else {
+ int ret = mm_display_interface_evas_set_visible(_mmDisplay, _visible);
+ if (ret != MM_ERROR_NONE)
+ LOG_ERROR("mm_display_interface_evas_set_visible failed 0x%x", ret);
+ }
}
void MediaTransporterDisplay::applyModeProperty()
{
- if (g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(_sinkElement)), "display-geometry-method"))
- g_object_set(G_OBJECT(_sinkElement),
- "display-geometry-method", (gint)_mode, /* 0: letter box, 1: origin size, 2: full screen */
- NULL);
+ if (_type == MTPR_DISPLAY_TYPE_OVERLAY) {
+ if (g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(_sinkElement)), "display-geometry-method"))
+ g_object_set(G_OBJECT(_sinkElement),
+ "display-geometry-method", (gint)_mode, /* 0: letter box, 1: origin size, 2: full screen */
+ NULL);
+ } else {
+ int ret = mm_display_interface_evas_set_mode(_mmDisplay, static_cast<int>(_mode));
+ if (ret != MM_ERROR_NONE)
+ LOG_ERROR("mm_display_interface_evas_set_mode failed 0x%x", ret);
+ }
}
\ No newline at end of file
#include <sound_manager_internal.h>
#include <pulse/proplist.h>
#include <sstream>
+#include <gst/allocators/gsttizenmemory.h>
+#include <tbm_surface_internal.h>
using namespace tizen_media_transporter;
_audioCallback._callback = nullptr;
}
-static media_format_mimetype_e _getMediaFormatMimeType(const std::string& mime)
+static media_format_mimetype_e _getMediaFormatMimeType(const std::string& mime, GstStructure* structure = nullptr)
{
if (mime.find(gst::MEDIA_TYPE_AUDIO_AAC) != std::string::npos)
return MEDIA_FORMAT_AAC;
- else if (mime.find(gst::MEDIA_TYPE_AUDIO_OPUS) != std::string::npos)
+ if (mime.find(gst::MEDIA_TYPE_AUDIO_OPUS) != std::string::npos)
return MEDIA_FORMAT_OPUS;
- else if (mime.find(gst::MEDIA_TYPE_AUDIO_VORBIS) != std::string::npos)
+ if (mime.find(gst::MEDIA_TYPE_AUDIO_VORBIS) != std::string::npos)
return MEDIA_FORMAT_VORBIS;
- else if (mime.find(gst::MEDIA_TYPE_VIDEO_MPEG) != std::string::npos)
+ if (mime.find(gst::MEDIA_TYPE_VIDEO_MPEG) != std::string::npos)
return MEDIA_FORMAT_MPEG4_SP; /* FIXME: need to check format , MEDIA_FORMAT_MPEG4_ASP */
- else if (mime.find(gst::MEDIA_TYPE_VIDEO_VP8) != std::string::npos)
+ if (mime.find(gst::MEDIA_TYPE_VIDEO_VP8) != std::string::npos)
return MEDIA_FORMAT_VP8;
- else if (mime.find(gst::MEDIA_TYPE_VIDEO_VP9) != std::string::npos)
+ if (mime.find(gst::MEDIA_TYPE_VIDEO_VP9) != std::string::npos)
return MEDIA_FORMAT_VP9;
- else if (mime.find(gst::MEDIA_TYPE_VIDEO_H264) != std::string::npos)
+ if (mime.find(gst::MEDIA_TYPE_VIDEO_H264) != std::string::npos)
return MEDIA_FORMAT_H264_HP;
- else if (mime.find(gst::MEDIA_TYPE_VIDEO_JPEG) != std::string::npos)
+ if (mime.find(gst::MEDIA_TYPE_VIDEO_JPEG) != std::string::npos)
return MEDIA_FORMAT_MJPEG;
+ if ((mime.find(gst::MEDIA_TYPE_VIDEO_RAW) != std::string::npos) && (structure != nullptr)) {
+ std::string format = gst_structure_get_string(structure, "format");
+ if (format.empty()) {
+ LOG_ERROR("format is empty");
+ return MEDIA_FORMAT_MAX;
+ }
+
+ if (format.find(gst::MEDIA_VIDEO_RAW_FORMAT_I420) != std::string::npos)
+ return MEDIA_FORMAT_I420;
+ if (format.find(gst::MEDIA_VIDEO_RAW_FORMAT_NV12) != std::string::npos
+ || format.find(gst::MEDIA_VIDEO_RAW_FORMAT_SN12) != std::string::npos)
+ return MEDIA_FORMAT_NV12;
+
+ LOG_ERROR("not supported format[%s]", format.c_str());
+ return MEDIA_FORMAT_MAX;
+ }
LOG_ERROR("not supported mime[%s]", mime.c_str());
return MEDIA_FORMAT_MAX;
GstStructure* structure = gst_caps_get_structure(caps, 0);
std::string mime = gst_structure_get_name(structure);
- media_format_mimetype_e mimetype = _getMediaFormatMimeType(mime);
+ media_format_mimetype_e mimetype = _getMediaFormatMimeType(mime, structure);
LOG_INFO("media format mimetype[0x%x]", mimetype);
if (mimetype & MEDIA_FORMAT_VIDEO) {
try {
// display RM acquire
- _resourceManager->acquire(RES_TYPE_VIDEO_OVERLAY);
+ if (_display->getType() == MTPR_DISPLAY_TYPE_OVERLAY)
+ _resourceManager->acquire(RES_TYPE_VIDEO_OVERLAY);
converter = gst::_createElement(gst::DEFAULT_ELEMENT_VIDEOCONVERT);
elements.push_back(converter);
sink = _display->videoSink();
}
}
+static uint32_t __convertToTbmFormat(const gchar *data)
+{
+ uint32_t fourcc = GST_STR_FOURCC(data);
+
+ switch (fourcc) {
+ case GST_STR_FOURCC("S420"):
+ case GST_STR_FOURCC("I420"):
+ return TBM_FORMAT_YUV420;
+ case GST_STR_FOURCC("BGRA"):
+ return TBM_FORMAT_BGRA8888;
+ case GST_STR_FOURCC("BGRx"):
+ return TBM_FORMAT_BGRX8888;
+ case GST_STR_FOURCC("SR32"):
+ return TBM_FORMAT_ARGB8888;
+ default:
+ LOG_ERROR("Not supported format %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS(fourcc));
+ return 0;
+ }
+}
+
+constexpr int kMaxPlane = 4;
+static tbm_surface_h __createTbmSurface(GstMemory* mem, GstCaps* caps)
+{
+ int ret = 0;
+ bool is_mapped = false;
+ int width = 0;
+ int height = 0;
+ uint32_t bo_format = 0;
+ const gchar* string_format = nullptr;
+ GstStructure* structure = nullptr;
+ GstMapInfo mapinfo = GST_MAP_INFO_INIT;
+ tbm_surface_h tbmSurf = nullptr;
+ tbm_surface_info_s info;
+ tbm_bo bo = nullptr;
+ uint32_t bo_size = 0;
+ tbm_bo_handle thandle = {nullptr, };
+
+ int plane_stride[kMaxPlane] = { 0, };
+ int plane_elevation[kMaxPlane] = { 0, };
+ int src_stride[kMaxPlane] = { 0, };
+ int src_offset[kMaxPlane] = { 0, };
+ int dest_offset[kMaxPlane] = { 0, };
+ int i = 0;
+ int j = 0;
+ int k = 0;
+ unsigned char *src = NULL;
+ unsigned char *dest = NULL;
+
+ if (!caps) {
+ LOG_ERROR("invalid caps");
+ return nullptr;
+ }
+
+ is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READ);
+ if (!is_mapped) {
+ LOG_ERROR("gst_memory_map fail");
+ return nullptr;
+ }
+
+ if (!mapinfo.data) {
+ LOG_ERROR("data pointer is wrong");
+ goto ERROR_CREATE;
+ }
+
+ structure = gst_caps_get_structure(caps, 0);
+ gst_structure_get_int(structure, "width", &width);
+ gst_structure_get_int(structure, "height", &height);
+ string_format = gst_structure_get_string(structure, "format");
+
+ bo_format = __convertToTbmFormat(string_format);
+ if (!bo_format) {
+ LOG_ERROR("not supported video format (%s)", string_format);
+ goto ERROR_CREATE;
+ }
+
+ tbmSurf = tbm_surface_create(width, height, bo_format);
+ if (!tbmSurf) {
+ LOG_ERROR("fail to create tbm surface");
+ goto ERROR_CREATE;
+ }
+
+ ret = tbm_surface_get_info(tbmSurf, &info);
+ if (ret != TBM_SURFACE_ERROR_NONE) {
+ LOG_ERROR("fail to get tbm surface info");
+ goto ERROR_CREATE;
+ }
+
+ bo = tbm_surface_internal_get_bo(tbmSurf, 0);
+ bo_size = tbm_bo_size(bo);
+ thandle = tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_WRITE);
+ if (!thandle.ptr) {
+ LOG_ERROR("thandle pointer is wrong");
+ goto ERROR_CREATE;
+ }
+
+ LOG_DEBUG("width %d, height %d, bo_size %d", width, height, bo_size);
+
+ switch (bo_format) {
+ case TBM_FORMAT_YUV420:
+ plane_stride[0] = info.planes[0].stride;
+ plane_elevation[0] = info.planes[0].size / info.planes[0].stride;
+ plane_stride[1] = info.planes[1].stride;
+ plane_elevation[1] = info.planes[1].size / info.planes[1].stride;
+ plane_stride[2] = info.planes[2].stride;
+ plane_elevation[2] = info.planes[2].size / info.planes[2].stride;
+
+ src_stride[0] = GST_ROUND_UP_4(width);
+ src_stride[1] = src_stride[2] = GST_ROUND_UP_4(width >> 1);
+ src_offset[1] = src_stride[0] * GST_ROUND_UP_2(height);
+ src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(height) >> 1));
+
+ dest_offset[0] = 0;
+ dest_offset[1] = plane_stride[0] * plane_elevation[0];
+ dest_offset[2] = dest_offset[1] + plane_stride[1] * plane_elevation[1];
+
+ for (i = 0; i < 3; i++) {
+ src = mapinfo.data + src_offset[i];
+ dest = static_cast<unsigned char*>(thandle.ptr) + dest_offset[i];
+
+ if (i > 0)
+ k = 1;
+
+ for (j = 0; j < height >> k; j++) {
+ memcpy(dest, src, width>>k);
+ src += src_stride[i];
+ dest += plane_stride[i];
+ }
+ }
+ break;
+ case TBM_FORMAT_BGRA8888:
+ case TBM_FORMAT_BGRX8888:
+ case TBM_FORMAT_ARGB8888:
+ memcpy(thandle.ptr, mapinfo.data, bo_size);
+ break;
+ default:
+ LOG_ERROR("not supported format");
+ goto ERROR_CREATE;
+ }
+
+ tbm_bo_unmap(bo);
+ gst_memory_unmap(mem, &mapinfo);
+
+ return tbmSurf;
+
+ERROR_CREATE:
+ if (bo)
+ tbm_bo_unmap(bo);
+
+ if (tbmSurf)
+ tbm_surface_destroy(tbmSurf);
+
+ gst_memory_unmap(mem, &mapinfo);
+ return nullptr;
+}
+
+static void __mediaPacketDisposeCallBack(media_packet_h pkt, void *user_data)
+{
+ int ret = 0;
+ tbm_surface_h tsurf = NULL;
+ GstBuffer* buffer = static_cast<GstBuffer*>(user_data);
+
+ if (!pkt || !buffer) {
+ LOG_ERROR("pkt or buffer is nullptr");
+ return;
+ }
+
+ ret = media_packet_get_tbm_surface(pkt, &tsurf);
+ if ((ret == MEDIA_PACKET_ERROR_NONE) && tsurf)
+ tbm_surface_destroy(tsurf);
+
+ gst_buffer_unref(buffer);
+}
+
+void MediaTransporterReceiver::_evasVideoCallback(GstElement* object, GstBuffer* buffer, GstPad* pad, gpointer data)
+{
+ MediaTransporterReceiver* mtprReceiver = static_cast<MediaTransporterReceiver*>(data);
+ if (mtprReceiver->_evasMediaFormat == nullptr) {
+ mtprReceiver->_evasMediaFormat = _makeMediaFormat(pad);
+ if (mtprReceiver->_evasMediaFormat == nullptr) {
+ LOG_ERROR("Failed to make evas media format");
+ return;
+ }
+ }
+
+ GstMemory* mem = gst_buffer_peek_memory(buffer, 0);
+ RET_IF(!mem, "Failed to get memory from buffer");
+ tbm_surface_h tbmSurf = nullptr;
+ if (gst_is_tizen_memory(mem)) {
+ tbmSurf = static_cast<tbm_surface_h>(gst_tizen_memory_get_surface(mem));
+ tbm_surface_internal_ref(tbmSurf);
+ } else {
+ GstCaps* caps = gst_pad_has_current_caps(pad) ? gst_pad_get_current_caps(pad) : gst_pad_query_caps(pad, NULL);
+ tbmSurf = __createTbmSurface(mem, caps);
+ gst_caps_unref(caps);
+ }
+
+ RET_IF(!tbmSurf, "tbm surface is nullptr");
+
+ media_packet_h packet = nullptr;
+ if (media_packet_new_from_tbm_surface(mtprReceiver->_evasMediaFormat, tbmSurf, __mediaPacketDisposeCallBack, buffer, &packet) != MEDIA_PACKET_ERROR_NONE) {
+ LOG_ERROR("media_packet_new_from_tbm_surface() failed");
+ tbm_surface_destroy(tbmSurf);
+ return;
+ }
+
+ gst_buffer_ref(buffer);
+ mm_display_interface_evas_render(mtprReceiver->_display->getMmDisplayHandle(), packet);
+}
+
int MediaTransporterReceiver::_buildRenderingElements(GstElement* demux, GstPad* pad, bool isAudio)
{
gst::GstElements elements;
else
_buildVideoRenderingSink(elements);
+ if (_display->getType() == MTPR_DISPLAY_TYPE_EVAS) {
+ // g_object_set(_display->getSinkElement(), "sync", TRUE, "signal-handoffs", TRUE, NULL);
+ g_object_set(_display->getSinkElement(), "signal-handoffs", TRUE, NULL);
+ gst::_connectAndAppendSignal(&_gst.signals, G_OBJECT(_display->getSinkElement()),
+ "preroll-handoff", G_CALLBACK(_evasVideoCallback), this);
+ gst::_connectAndAppendSignal(&_gst.signals, G_OBJECT(_display->getSinkElement()),
+ "handoff", G_CALLBACK(_evasVideoCallback), this);
+ }
+
std::string binName = isAudio ? "renderingAudioBin" : "renderingVideoBin";
GstBin* bin = GST_BIN(gst_bin_new(binName.c_str()));