From: Hyongtaek Lim Date: Mon, 10 Aug 2015 11:42:18 +0000 (+0900) Subject: Replace capi-meida-player with deamon X-Git-Tag: submit/tizen/20150812.014234^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2aa3250e99ec28c531ff883c9707b8aa6073da62;p=platform%2Fcore%2Fmultimedia%2Flibmm-player.git Replace capi-meida-player with deamon Signed-off-by: Hyongtaek Lim Change-Id: Ib2e09a52592fa35ab5246d1dcf86184a41ef3336 --- diff --git a/Makefile.am b/Makefile.am index 4234d3f..63ba01d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ -ACLOCAL_AMFLAGS='-I m4' +ACLOCAL_AMFLAGS='-I m4' SUBDIRS = src -pcfiles = mm-player.pc +pcfiles = mm-player.pc mm-playerclient.pc pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = $(pcfiles) EXTRA_DIST = $(pcfiles) diff --git a/configure.ac b/configure.ac old mode 100755 new mode 100644 index 647c5f1..a32c24a --- a/configure.ac +++ b/configure.ac @@ -3,9 +3,9 @@ AC_PREREQ(2.61) AC_INIT([libmm-player],[0.3.0]) -AC_CONFIG_SRCDIR([src/mm_player_priv.c]) +AC_CONFIG_SRCDIR([src]) AC_CONFIG_HEADER([config.h]) -AM_INIT_AUTOMAKE([-Wall foreign]) +AM_INIT_AUTOMAKE([-Wall foreign subdir-objects]) # Checks for programs. m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) @@ -136,5 +136,6 @@ AM_CONDITIONAL([IS_SDK], [test "x$IS_SDK" = "xyes"]) AC_CONFIG_FILES([Makefile src/Makefile mm-player.pc + mm-playerclient.pc ]) AC_OUTPUT diff --git a/mm-playerclient.pc.in b/mm-playerclient.pc.in new file mode 100644 index 0000000..924eb51 --- /dev/null +++ b/mm-playerclient.pc.in @@ -0,0 +1,11 @@ +prefix = @prefix@ +exec_prefix=@exec_prefix@ +libdir = @libdir@ +includedir = @includedir@ + +Name : mm-playerclient +Description : Multimedia Framework Player Library +Requires : mm-common +Version : @VERSION@ +Libs : -L${libdir} -lmmfplayerclient +Cflags : -I${includedir}/mmf diff --git a/src/Makefile.am b/src/Makefile.am index 9e4159b..dad5fcb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,25 +1,30 @@ -lib_LTLIBRARIES = libmmfplayer.la +lib_LTLIBRARIES = libmmfplayer.la libmmfplayerclient.la includelibmmfplayerdir = $(includedir)/mmf includelibmmfplayer_HEADERS = include/mm_player.h \ include/mm_player_internal.h \ include/mm_player_audioeffect.h \ - include/mused/mm_player_mused.h + include/mm_player_mused.h -libmmfplayer_la_SOURCES = mm_player.c \ - mm_player_priv.c \ - mm_player_ini.c \ - mm_player_utils.c \ - mm_player_sound_focus.c \ +libmmfplayer_la_SOURCES = server/mm_player.c \ + server/mm_player_priv.c \ + server/mm_player_utils.c \ + server/mm_player_sound_focus.c \ + server/mm_player_capture.c \ + server/mm_player_pd.c \ + server/mm_player_streaming.c \ + server/mm_player_tracks.c \ + server/mm_player_audioeffect.c \ + server/mm_player_es.c \ + mm_player_common_priv.c \ mm_player_attrs.c \ - mm_player_capture.c \ - mm_player_pd.c \ - mm_player_streaming.c \ - mm_player_tracks.c \ - mm_player_audioeffect.c \ - mm_player_es.c \ - mused/mm_player_mused.c + mm_player_ini.c + +libmmfplayerclient_la_SOURCES = client/mm_player_client.c \ + mm_player_common_priv.c \ + mm_player_attrs.c \ + mm_player_ini.c libmmfplayer_la_CFLAGS = -I$(srcdir)/include \ $(MMCOMMON_CFLAGS) \ @@ -35,6 +40,15 @@ libmmfplayer_la_CFLAGS = -I$(srcdir)/include \ $(MEDIAPACKET_CFLAGS) \ -Werror -Wno-deprecated -Wno-deprecated-declarations -Wno-cpp +libmmfplayerclient_la_CFLAGS = -I$(srcdir)/include \ + $(MMCOMMON_CFLAGS) \ + $(MMUTIL_CFLAGS) \ + $(GST_CFLAGS) \ + $(GST_VIDEO_CFLAGS) \ + $(GST_APP_CFLAGS) \ + $(VCONF_CFLAGS) \ + -Werror -Wno-deprecated -Wno-deprecated-declarations -Wno-cpp + noinst_HEADERS = include/mm_player_utils.h \ include/mm_player_ini.h \ include/mm_player_priv.h \ @@ -60,9 +74,21 @@ libmmfplayer_la_LIBADD = $(GST_LIBS) \ $(MEDIAPACKET_LIBS) \ $(UTILX_LIBS) +libmmfplayerclient_la_LIBADD = $(GST_LIBS) \ + $(MMCOMMON_LIBS) \ + $(MMUTIL_LIBS) \ + $(GST_INTERFACE_LIBS) \ + $(GST_VIDEO_LIBS) \ + $(GST_APP_LIBS) \ + $(INIPARSER_LIBS) \ + $(VCONF_LIBS) + libmmfplayer_la_CFLAGS += $(MMLOG_CFLAGS) -DMMF_LOG_OWNER=0x008 -DMMF_DEBUG_PREFIX=\"MMF-PLAYER\" -D_INTERNAL_SESSION_MANAGER_ libmmfplayer_la_LIBADD += $(MMLOG_LIBS) +libmmfplayerclient_la_CFLAGS += $(MMLOG_CFLAGS) -DMMF_LOG_OWNER=0x008 -DMMF_DEBUG_PREFIX=\"MMF-PLAYER\" -D_INTERNAL_SESSION_MANAGER_ +libmmfplayerclient_la_LIBADD += $(MMLOG_LIBS) + if IS_SDK libmmfplayer_la_CFLAGS += -DIS_SDK endif @@ -70,4 +96,6 @@ endif if WAYLAND_SUPPORT libmmfplayer_la_CFLAGS += $(GST_WAYLAND_CFLAGS) libmmfplayer_la_LIBADD += $(GST_WAYLAND_LIBS) +libmmfplayerclient_la_CFLAGS += $(GST_WAYLAND_CFLAGS) +libmmfplayerclient_la_LIBADD += $(GST_WAYLAND_LIBS) endif diff --git a/src/client/mm_player_client.c b/src/client/mm_player_client.c new file mode 100644 index 0000000..2de6e42 --- /dev/null +++ b/src/client/mm_player_client.c @@ -0,0 +1,1159 @@ +/* + * libmm-player + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: YoungHwan An + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*=========================================================================================== +| | +| INCLUDE FILES | +| | +========================================================================================== */ +#include +#include +#include +#include +#ifdef HAVE_WAYLAND +#include +#endif +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "mm_player_priv.h" +#include "mm_player_ini.h" +#include "mm_player_attrs.h" +#include "mm_player_utils.h" +#include + +/*=========================================================================================== +| | +| LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE | +| | +========================================================================================== */ + +/*--------------------------------------------------------------------------- +| GLOBAL CONSTANT DEFINITIONS: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| IMPORTED VARIABLE DECLARATIONS: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| IMPORTED FUNCTION DECLARATIONS: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| LOCAL #defines: | +---------------------------------------------------------------------------*/ +/* setting player state */ +#define MMPLAYER_MUSED_SET_STATE( x_player, x_state ) \ +debug_log("update state machine to %d\n", x_state); \ +__mmplayer_mused_set_state(x_player, x_state); + +/*--------------------------------------------------------------------------- +| LOCAL CONSTANT DEFINITIONS: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| LOCAL DATA TYPE DEFINITIONS: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| GLOBAL VARIABLE DEFINITIONS: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| LOCAL VARIABLE DEFINITIONS: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| LOCAL FUNCTION PROTOTYPES: | +---------------------------------------------------------------------------*/ +static gboolean _mmplayer_mused_init_gst(mm_player_t* player); +static int _mmplayer_mused_realize(mm_player_t *player, char *string_caps); +static int _mmplayer_mused_unrealize(mm_player_t *player); +static MMHandleType _mmplayer_mused_construct_attribute(mm_player_t *player); +static int _mmplayer_mused_update_video_param(mm_player_t *player); +static int __mmplayer_mused_gst_destroy_pipeline(mm_player_t *player); +static int _mmplayer_mused_gst_pause(mm_player_t *player); +static gboolean __mmplayer_mused_gst_callback(GstBus *bus, GstMessage *msg, gpointer data); +static GstBusSyncReply __mmplayer_mused_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data); +static int __mmplayer_mused_set_state(mm_player_t* player, int state); +/*=========================================================================================== +| | +| FUNCTION DEFINITIONS | +| | +========================================================================================== */ + +int mm_player_mused_create(MMHandleType *player) +{ + int result = MM_ERROR_NONE; + mm_player_t* new_player = NULL; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + /* alloc player structure */ + new_player = g_malloc0(sizeof(mm_player_t)); + if ( ! new_player ) + { + debug_error("Cannot allocate memory for player\n"); + goto ERROR; + } + + /* create player lock */ + g_mutex_init(&new_player->cmd_lock); + + /* load ini files */ + result = mm_player_ini_load(&new_player->ini); + if(result != MM_ERROR_NONE) + { + debug_error("can't load ini"); + goto ERROR; + } + + /* initialize player state */ + MMPLAYER_CURRENT_STATE(new_player) = MM_PLAYER_STATE_NONE; + MMPLAYER_PREV_STATE(new_player) = MM_PLAYER_STATE_NONE; + MMPLAYER_PENDING_STATE(new_player) = MM_PLAYER_STATE_NONE; + MMPLAYER_TARGET_STATE(new_player) = MM_PLAYER_STATE_NONE; + + /* check current state */ + if (__mmplayer_check_state ( new_player, MMPLAYER_COMMAND_CREATE ) + != MM_ERROR_NONE) + goto ERROR; + + /* construct attributes */ + new_player->attrs = _mmplayer_mused_construct_attribute(new_player); + + if ( !new_player->attrs ) + { + debug_error("Failed to construct attributes\n"); + goto ERROR; + } + + /* initialize gstreamer with configured parameter */ + if ( ! _mmplayer_mused_init_gst(new_player) ) + { + debug_error("Initializing gstreamer failed\n"); + goto ERROR; + } + MMPLAYER_MUSED_SET_STATE ( new_player, MM_PLAYER_STATE_NULL ); + MMPLAYER_STATE_CHANGE_TIMEOUT(new_player) = new_player->ini.localplayback_state_change_timeout; + + *player = (MMHandleType)new_player; + return result; +ERROR: + if( new_player ) { + g_mutex_clear(&new_player->cmd_lock); + _mmplayer_deconstruct_attribute(new_player); + g_free( new_player ); + } + + *player = NULL; + return MM_ERROR_PLAYER_NO_FREE_SPACE; +} + +static gboolean +_mmplayer_mused_init_gst(mm_player_t *player) +{ + static gboolean initialized = FALSE; + static const int max_argc = 50; + gint* argc = NULL; + gchar** argv = NULL; + gchar** argv2 = NULL; + GError *err = NULL; + int i = 0; + int arg_count = 0; + + if ( initialized ) + { + debug_log("gstreamer already initialized.\n"); + return TRUE; + } + + /* alloc */ + argc = malloc( sizeof(int) ); + argv = malloc( sizeof(gchar*) * max_argc ); + argv2 = malloc( sizeof(gchar*) * max_argc ); + + if ( !argc || !argv || !argv2) + goto GST_INIT_EXIT; + + memset( argv, 0, sizeof(gchar*) * max_argc ); + memset( argv2, 0, sizeof(gchar*) * max_argc ); + + /* add initial */ + *argc = 1; + argv[0] = g_strdup( "mused_client" ); + + /* add gst_param */ + for ( i = 0; i < 5; i++ ) /* FIXIT : num of param is now fixed to 5. make it dynamic */ + { + if ( strlen( player->ini.gst_param[i] ) > 0 ) + { + argv[*argc] = g_strdup( player->ini.gst_param[i] ); + (*argc)++; + } + } + + /* we would not do fork for scanning plugins */ + argv[*argc] = g_strdup("--gst-disable-registry-fork"); + (*argc)++; + + /* check disable registry scan */ + if ( player->ini.skip_rescan ) + { + argv[*argc] = g_strdup("--gst-disable-registry-update"); + (*argc)++; + } + + /* check disable segtrap */ + if ( player->ini.disable_segtrap ) + { + argv[*argc] = g_strdup("--gst-disable-segtrap"); + (*argc)++; + } + + arg_count = *argc; + + for ( i = 0; i < arg_count; i++ ) + argv2[i] = argv[i]; + + /* initializing gstreamer */ + if ( ! gst_init_check (argc, &argv, &err)) + { + debug_error("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred"); + if (err) + { + g_error_free (err); + } + } + + initialized = TRUE; +GST_INIT_EXIT: + /* release */ + for ( i = 0; i < arg_count; i++ ) + { + MMPLAYER_FREEIF( argv2[i] ); + } + + MMPLAYER_FREEIF( argv ); + MMPLAYER_FREEIF( argv2 ); + MMPLAYER_FREEIF( argc ); + + return initialized; +} + +int mm_player_mused_destroy(MMHandleType player) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + /* destroy can called at anytime */ + MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_DESTROY ); + + __mmplayer_mused_gst_destroy_pipeline(player); + + /* release attributes */ + if( !_mmplayer_deconstruct_attribute( player ) ) { + debug_error("failed to deconstruct attribute"); + result = MM_ERROR_PLAYER_INTERNAL; + } + + MMPLAYER_CMD_UNLOCK( player ); + + g_mutex_clear(&((mm_player_t*)player)->cmd_lock); + g_free( player ); + return result; +} + + +int mm_player_mused_realize(MMHandleType player, char *caps) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_mused_realize((mm_player_t *)player, caps); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +static int _mmplayer_mused_realize(mm_player_t *player, char *string_caps) +{ + int result = MM_ERROR_NONE; + GstElement *src; + GstElement *sink; + GstBus *bus; + GstCaps *caps; + MMPlayerGstElement *mainbin = NULL; + MMHandleType attrs = MMPLAYER_GET_ATTRS(player); + int width = 0; + int height = 0; + gboolean link; + char *stream_path = NULL; + int attr_ret; + int surface_type = 0; + gchar *videosink_element = NULL; + gchar *videosrc_element = NULL; + + /* check current state */ + MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_REALIZE ); + + /* create pipeline handles */ + if ( player->pipeline ) + { + debug_warning("pipeline should be released before create new one\n"); + return result; + } + /* alloc handles */ + player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0( sizeof(MMPlayerGstPipelineInfo) ); + if (player->pipeline == NULL) + return MM_ERROR_PLAYER_NO_FREE_SPACE; + + /* create mainbin */ + mainbin = (MMPlayerGstElement*) g_malloc0( sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM ); + if (!mainbin) { + result = MM_ERROR_OUT_OF_MEMORY; + goto REALIZE_ERROR; + } + + /* create pipeline */ + mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE; + mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("playerClient"); + debug_log("gst new %p", mainbin[MMPLAYER_M_PIPE].gst); + if ( ! mainbin[MMPLAYER_M_PIPE].gst ) + { + debug_error("failed to create pipeline\n"); + result = MM_ERROR_PLAYER_INTERNAL; + goto REALIZE_ERROR; + } + + if (strlen(player->ini.videosrc_element_remote) > 0) + videosrc_element = player->ini.videosrc_element_remote; + else { + debug_error("fail to find source element"); + result = MM_ERROR_PLAYER_INTERNAL; + goto REALIZE_ERROR; + } + + /* create source */ + src = gst_element_factory_make(videosrc_element, videosrc_element); + if ( !src ) { + debug_error("faile to create %s", videosrc_element); + result = MM_ERROR_PLAYER_INTERNAL; + goto REALIZE_ERROR; + } + if(strcmp(videosrc_element, "shmsrc") == 0) { + attr_ret = mm_attrs_get_string_by_name ( attrs, "shm_stream_path", &stream_path ); + if(attr_ret == MM_ERROR_NONE && stream_path) { + LOGD("stream path : %s", stream_path); + g_object_set(G_OBJECT(src), + "socket-path", stream_path, + "is-live", TRUE, + NULL); + } else { + result = MM_ERROR_PLAYER_INTERNAL; + goto REALIZE_ERROR; + } + } + + mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC; + mainbin[MMPLAYER_M_SRC].gst = src; + + /* create sink */ + mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type); + switch(surface_type) + { + case MM_DISPLAY_SURFACE_X: + if (strlen(player->ini.videosink_element_x) > 0) + videosink_element = player->ini.videosink_element_x; + else { + result = MM_ERROR_PLAYER_NOT_INITIALIZED; + goto REALIZE_ERROR; + } + break; + default: + debug_error("Not support surface type %d", surface_type); + result = MM_ERROR_INVALID_ARGUMENT; + goto REALIZE_ERROR; + } + sink = gst_element_factory_make(videosink_element, videosink_element); + if ( !src ) { + debug_error("faile to create %s", videosink_element); + result = MM_ERROR_PLAYER_INTERNAL; + goto REALIZE_ERROR; + } + mainbin[MMPLAYER_M_V_SINK].id = MMPLAYER_M_V_SINK; + mainbin[MMPLAYER_M_V_SINK].gst = sink; + + /* now we have completed mainbin. take it */ + player->pipeline->mainbin = mainbin; + + result = _mmplayer_mused_update_video_param(player); + if(result != MM_ERROR_NONE) + goto REALIZE_ERROR; + + /* add and link */ + gst_bin_add_many(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), + mainbin[MMPLAYER_M_SRC].gst, + mainbin[MMPLAYER_M_V_SINK].gst, + NULL); + + mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &width); + mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &height); + + caps = gst_caps_from_string(string_caps); + + link = gst_element_link_filtered(mainbin[MMPLAYER_M_SRC].gst, mainbin[MMPLAYER_M_V_SINK].gst, caps); + gst_caps_unref(caps); + if(!link) { + debug_error("element link error"); + result = MM_ERROR_PLAYER_INTERNAL; + goto REALIZE_ERROR; + } + + /* connect bus callback */ + bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst)); + if ( !bus ) { + debug_error ("cannot get bus from pipeline.\n"); + result = MM_ERROR_PLAYER_INTERNAL; + goto REALIZE_ERROR; + } + + player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_mused_gst_callback, player); + + player->context.thread_default = g_main_context_get_thread_default(); + + if (NULL == player->context.thread_default) + { + player->context.thread_default = g_main_context_default(); + debug_log("thread-default context is the global default context"); + } + debug_log("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher); + + /* set sync handler to get tag synchronously */ + gst_bus_set_sync_handler(bus, __mmplayer_mused_bus_sync_callback, player, NULL); + + gst_object_unref(GST_OBJECT(bus)); + + /* warm up */ + if ( GST_STATE_CHANGE_FAILURE == + gst_element_set_state(mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY ) ) { + debug_error("failed to set state(READY) to pipeline"); + result = MM_ERROR_PLAYER_INVALID_STATE; + goto REALIZE_ERROR; + } + /* run */ + if (GST_STATE_CHANGE_FAILURE == + gst_element_set_state (mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED)) { + debug_error("failed to set state(PAUSE) to pipeline"); + result = MM_ERROR_PLAYER_INVALID_STATE; + goto REALIZE_ERROR; + } + if (GST_STATE_CHANGE_FAILURE == + gst_element_set_state (mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING)) { + debug_error("failed to set state(PLAYING) to pipeline"); + result = MM_ERROR_PLAYER_INVALID_STATE; + goto REALIZE_ERROR; + } + + MMPLAYER_MUSED_SET_STATE ( player, MM_PLAYER_STATE_READY ); + return result; + +REALIZE_ERROR: + __mmplayer_mused_gst_destroy_pipeline(player); + return result; +} + +static int _mmplayer_mused_update_video_param(mm_player_t *player) +{ + MMHandleType attrs = 0; + int surface_type = 0; + MMPlayerGstElement* mainbin = player->pipeline->mainbin; + + if( !mainbin ) { + debug_error("mainbin was not created"); + return MM_ERROR_PLAYER_INTERNAL; + } + attrs = MMPLAYER_GET_ATTRS(player); + if ( !attrs ) { + debug_error("cannot get content attribute"); + return MM_ERROR_PLAYER_INTERNAL; + } + /* update display surface */ + mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type); + debug_log("check display surface type attribute: %d", surface_type); + + /* configuring display */ + switch ( surface_type ) + { + case MM_DISPLAY_SURFACE_X: + { + /* ximagesink or xvimagesink */ + void *surface = NULL; + +#ifdef HAVE_WAYLAND + /*set wl_display*/ + void* wl_display = NULL; + GstContext *context = NULL; + int wl_window_x = 0; + int wl_window_y = 0; + int wl_window_width = 0; + int wl_window_height = 0; + + mm_attrs_get_data_by_name(attrs, "wl_display", &wl_display); + if (wl_display) + context = gst_wayland_display_handle_context_new(wl_display); + if (context) + gst_element_set_context(GST_ELEMENT(mainbin[MMPLAYER_M_V_SINK].gst), context); + + /*It should be set after setting window*/ + mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x); + mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y); + mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width); + mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height); +#endif + mm_attrs_get_data_by_name(attrs, "display_overlay", &surface); + if ( surface ) { +#ifdef HAVE_WAYLAND + guintptr wl_surface = (guintptr)surface; + debug_log("set video param : surface %p", wl_surface); + gst_video_overlay_set_window_handle( + GST_VIDEO_OVERLAY( mainbin[MMPLAYER_M_V_SINK].gst ), + wl_surface ); + /* After setting window handle, set render rectangle */ + gst_video_overlay_set_render_rectangle( + GST_VIDEO_OVERLAY( mainbin[MMPLAYER_M_V_SINK].gst ), + wl_window_x,wl_window_y,wl_window_width,wl_window_height); +#else + int xwin_id = 0; + xwin_id = *(int*)surface; + debug_log("set video param : xid %d", xwin_id); + if (xwin_id) + { + gst_video_overlay_set_window_handle( + GST_VIDEO_OVERLAY( player->pipeline->videobin[MMPLAYER_V_SINK].gst ), + xwin_id ); + } +#endif + } + else + debug_warning("still we don't have surface on player attribute. create it's own surface."); + } + break; + default: + debug_log("Noting to update"); + break; + } + + return MM_ERROR_NONE; +} + +int mm_player_mused_unrealize(MMHandleType player) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_mused_unrealize(player); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +static int _mmplayer_mused_unrealize(mm_player_t *player) +{ + int ret = MM_ERROR_NONE; + + /* check current state */ + MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_UNREALIZE ); + + ret = __mmplayer_mused_gst_destroy_pipeline(player); + + MMPLAYER_MUSED_SET_STATE ( player, MM_PLAYER_STATE_NULL ); + + return ret; +} + +static int __mmplayer_mused_gst_destroy_pipeline(mm_player_t *player) +{ + int ret = MM_ERROR_NONE; + /* cleanup gst stuffs */ + if ( player->pipeline ) { + MMPlayerGstElement* mainbin = player->pipeline->mainbin; + + /* disconnecting bus watch */ + if ( player->bus_watcher ) + __mmplayer_remove_g_source_from_context( + player->context.thread_default, player->bus_watcher); + player->bus_watcher = 0; + + if ( mainbin ) { + gint timeout; + GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (mainbin[MMPLAYER_M_PIPE].gst)); + gst_bus_set_sync_handler (bus, NULL, NULL, NULL); + gst_object_unref(bus); + + timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player); + ret = __mmplayer_gst_set_state ( player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout ); + if ( ret != MM_ERROR_NONE ) { + debug_error("fail to change state to NULL\n"); + return MM_ERROR_PLAYER_INTERNAL; + } + debug_log("succeeded in chaning state to NULL\n"); + + debug_log("gst unref %p", mainbin[MMPLAYER_M_PIPE].gst); + gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst)); + + debug_log("free mainbin"); + MMPLAYER_FREEIF( player->pipeline->mainbin ); + } + debug_log("free pipelin"); + MMPLAYER_FREEIF( player->pipeline ); + } + debug_log("finished destroy pipeline"); + + return ret; +} + +static int _mmplayer_mused_gst_pause(mm_player_t *player) +{ + /* check current state */ + MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_UNREALIZE ); + + int ret = MM_ERROR_NONE; + if ( player->pipeline ) { + MMPlayerGstElement* mainbin = player->pipeline->mainbin; + + if ( mainbin ) { + gint timeout; + + timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player); + ret = __mmplayer_gst_set_state ( player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout ); + if ( ret != MM_ERROR_NONE ) { + debug_error("fail to change state to PAUSED"); + return MM_ERROR_PLAYER_INTERNAL; + } + debug_log("succeeded in chaning state to PAUSED"); + MMPLAYER_MUSED_SET_STATE ( player, MM_PLAYER_STATE_PAUSED ); + } + } + + return MM_ERROR_NONE; +} + +int mm_player_mused_pre_unrealize(MMHandleType player) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_mused_gst_pause(player); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_attribute(MMHandleType player, char **err_attr_name, const char *first_attribute_name, ...) +{ + int result = MM_ERROR_NONE; + va_list var_args; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(first_attribute_name, MM_ERROR_COMMON_INVALID_ARGUMENT); + + va_start (var_args, first_attribute_name); + result = _mmplayer_set_attribute(player, err_attr_name, first_attribute_name, var_args); + va_end (var_args); + + return result; +} + +static MMHandleType _mmplayer_mused_construct_attribute(mm_player_t *player) +{ + int idx = 0; + MMHandleType attrs = 0; + int num_of_attrs = 0; + mmf_attrs_construct_info_t *base = NULL; + + MMPlayerAttrsSpec player_attrs[] = + { + { + "display_surface_type", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) MM_DISPLAY_SURFACE_NULL, + MM_ATTRS_VALID_TYPE_INT_RANGE, + MM_DISPLAY_SURFACE_X, + MM_DISPLAY_SURFACE_X_EXT + }, + { + "display_overlay", + MM_ATTRS_TYPE_DATA, + MM_ATTRS_FLAG_RW, + (void *) NULL, + MM_ATTRS_VALID_TYPE_NONE, + 0, + 0 + }, +#ifdef HAVE_WAYLAND + { + "wl_display", + MM_ATTRS_TYPE_DATA, + MM_ATTRS_FLAG_RW, + (void *) NULL, + MM_ATTRS_VALID_TYPE_NONE, + 0, + 0 + }, + { + "wl_window_render_x", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) 0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + MMPLAYER_MAX_INT + }, + { + "wl_window_render_y", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) 0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + MMPLAYER_MAX_INT + }, + { + "wl_window_render_width", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) 0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + MMPLAYER_MAX_INT + }, + { + "wl_window_render_height", + MM_ATTRS_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void *) 0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + MMPLAYER_MAX_INT + }, +#endif + { + "shm_stream_path", + MM_ATTRS_TYPE_STRING, + MM_ATTRS_FLAG_RW, + (void *) NULL, + MM_ATTRS_VALID_TYPE_NONE, + 0, + 0 + } + }; + num_of_attrs = ARRAY_SIZE(player_attrs); + base = (mmf_attrs_construct_info_t* )malloc(num_of_attrs * sizeof(mmf_attrs_construct_info_t)); + if ( !base ) + { + debug_error("failed to alloc attrs constructor"); + return 0; + } + + /* initialize values of attributes */ + for ( idx = 0; idx < num_of_attrs; idx++ ) + { + base[idx].name = player_attrs[idx].name; + base[idx].value_type = player_attrs[idx].value_type; + base[idx].flags = player_attrs[idx].flags; + base[idx].default_value = player_attrs[idx].default_value; + } + + attrs = mmf_attrs_new_from_data( + "mmplayer_attrs", + base, + num_of_attrs, + NULL, + NULL); + + /* clean */ + MMPLAYER_FREEIF(base); + + if ( !attrs ) + { + debug_error("failed to create player attrs"); + return 0; + } + + /* set validity type and range */ + for ( idx = 0; idx < num_of_attrs; idx++ ) + { + switch ( player_attrs[idx].valid_type) + { + case MM_ATTRS_VALID_TYPE_INT_RANGE: + { + mmf_attrs_set_valid_type (attrs, idx, MM_ATTRS_VALID_TYPE_INT_RANGE); + mmf_attrs_set_valid_range (attrs, idx, + player_attrs[idx].value_min, + player_attrs[idx].value_max, + (int)(intptr_t)(player_attrs[idx].default_value)); + } + break; + + case MM_ATTRS_VALID_TYPE_INT_ARRAY: + case MM_ATTRS_VALID_TYPE_DOUBLE_ARRAY: + case MM_ATTRS_VALID_TYPE_DOUBLE_RANGE: + default: + break; + } + } + + /* commit */ + mmf_attrs_commit(attrs); + + return attrs; +} + + +static GstBusSyncReply +__mmplayer_mused_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data) +{ + mm_player_t *player = (mm_player_t *)data; + GstBusSyncReply reply = GST_BUS_DROP; + + if ( ! ( player->pipeline && player->pipeline->mainbin ) ) + { + debug_error("player pipeline handle is null"); + return GST_BUS_PASS; + } + + if (!__mmplayer_check_useful_message(player, message)) + { + gst_message_unref (message); + return GST_BUS_DROP; + } + + switch (GST_MESSAGE_TYPE (message)) + { + case GST_MESSAGE_STATE_CHANGED: + /* post directly for fast launch */ + if (player->sync_handler) { + __mmplayer_mused_gst_callback(NULL, message, player); + reply = GST_BUS_DROP; + } + else { + reply = GST_BUS_PASS; + } + break; + default: + reply = GST_BUS_PASS; + break; + } + + if (reply == GST_BUS_DROP) + gst_message_unref (message); + + return reply; +} + +static gboolean +__mmplayer_mused_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @ +{ + mm_player_t* player = (mm_player_t*) data; + gboolean ret = TRUE; + + return_val_if_fail ( player, FALSE ); + return_val_if_fail ( msg && GST_IS_MESSAGE(msg), FALSE ); + + switch ( GST_MESSAGE_TYPE( msg ) ) + { + case GST_MESSAGE_UNKNOWN: + debug_log("unknown message received\n"); + break; + + case GST_MESSAGE_EOS: + { + debug_log("GST_MESSAGE_EOS received\n"); + + /* NOTE : EOS event is comming multiple time. watch out it */ + /* check state. we only process EOS when pipeline state goes to PLAYING */ + if ( ! (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) ) + { + debug_log("EOS received on non-playing state. ignoring it\n"); + break; + } + } + break; + + case GST_MESSAGE_ERROR: + { + GError *error = NULL; + gchar* debug = NULL; + + /* generating debug info before returning error */ + MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-error" ); + + /* get error code */ + gst_message_parse_error( msg, &error, &debug ); + + /* traslate gst error code to msl error code. then post it + * to application if needed + */ + __mmplayer_handle_gst_error( player, msg, error ); + + if (debug) + { + debug_error ("error debug : %s", debug); + } + + MMPLAYER_FREEIF( debug ); + g_error_free( error ); + } + break; + + case GST_MESSAGE_WARNING: + { + char* debug = NULL; + GError* error = NULL; + + gst_message_parse_warning(msg, &error, &debug); + + debug_log("warning : %s\n", error->message); + debug_log("debug : %s\n", debug); + + MMPLAYER_FREEIF( debug ); + g_error_free( error ); + } + break; + + case GST_MESSAGE_TAG: + { + debug_log("GST_MESSAGE_TAG\n"); + } + break; + + case GST_MESSAGE_BUFFERING: + break; + + case GST_MESSAGE_STATE_CHANGED: + { + MMPlayerGstElement *mainbin; + const GValue *voldstate, *vnewstate, *vpending; + GstState oldstate, newstate, pending; + + if ( ! ( player->pipeline && player->pipeline->mainbin ) ) + { + debug_error("player pipeline handle is null"); + break; + } + + mainbin = player->pipeline->mainbin; + + /* we only handle messages from pipeline */ + if( msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst ) + break; + + /* get state info from msg */ + voldstate = gst_structure_get_value (gst_message_get_structure(msg), "old-state"); + vnewstate = gst_structure_get_value (gst_message_get_structure(msg), "new-state"); + vpending = gst_structure_get_value (gst_message_get_structure(msg), "pending-state"); + + oldstate = (GstState)voldstate->data[0].v_int; + newstate = (GstState)vnewstate->data[0].v_int; + pending = (GstState)vpending->data[0].v_int; + + debug_log("state changed [%s] : %s ---> %s final : %s\n", + GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), + gst_element_state_get_name( (GstState)oldstate ), + gst_element_state_get_name( (GstState)newstate ), + gst_element_state_get_name( (GstState)pending ) ); + + if (oldstate == newstate) + { + debug_log("pipeline reports state transition to old state"); + break; + } + + switch(newstate) + { + case GST_STATE_VOID_PENDING: + break; + + case GST_STATE_NULL: + break; + + case GST_STATE_READY: + break; + + case GST_STATE_PAUSED: + { + gboolean prepare_async = FALSE; + + if ( ! player->sent_bos && oldstate == GST_STATE_READY) // managed prepare async case + { + mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async); + debug_log("checking prepare mode for async transition - %d", prepare_async); + } + } + break; + + case GST_STATE_PLAYING: + break; + + default: + break; + } + } + break; + + case GST_MESSAGE_CLOCK_LOST: + { + GstClock *clock = NULL; + gst_message_parse_clock_lost (msg, &clock); + debug_log("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL")); + } + break; + + case GST_MESSAGE_NEW_CLOCK: + { + GstClock *clock = NULL; + gst_message_parse_new_clock (msg, &clock); + debug_log("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL")); + } + break; + + case GST_MESSAGE_ELEMENT: + { + debug_log("GST_MESSAGE_ELEMENT"); + } + break; + + case GST_MESSAGE_DURATION_CHANGED: + { + debug_log("GST_MESSAGE_DURATION_CHANGED"); + } + + break; + + case GST_MESSAGE_ASYNC_START: + { + debug_log("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg))); + } + break; + + case GST_MESSAGE_ASYNC_DONE: + { + debug_log("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg))); + } + break; + + default: + break; + } + + /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since + * gst_element_post_message api takes ownership of the message. + */ + //gst_message_unref( msg ); + + return ret; +} + +int mm_player_set_shm_stream_path(MMHandleType player, const char *path) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(path, MM_ERROR_INVALID_ARGUMENT); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_shm_stream_path(player, path); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; + +} + +static int __mmplayer_mused_set_state(mm_player_t* player, int state) +{ + int ret = MM_ERROR_NONE; + + return_val_if_fail ( player, FALSE ); + + if ( MMPLAYER_CURRENT_STATE(player) == state ) + { + debug_warning("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state)); + MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE; + return ret; + } + + /* update player states */ + MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player); + MMPLAYER_CURRENT_STATE(player) = state; + + /* FIXIT : it's better to do like below code + if ( MMPLAYER_CURRENT_STATE(player) == MMPLAYER_TARGET_STATE(player) ) + MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE; + and add more code to handling PENDING_STATE. + */ + if ( MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player) ) + MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE; + + /* print state */ + MMPLAYER_PRINT_STATE(player); + + /* post message to application */ + if (MMPLAYER_TARGET_STATE(player) == state) + { + debug_log ("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player))); + } + else + { + debug_log ("intermediate state, do nothing.\n"); + MMPLAYER_PRINT_STATE(player); + return ret; + } + + return ret; +} diff --git a/src/include/mm_player_mused.h b/src/include/mm_player_mused.h new file mode 100644 index 0000000..6cd83c5 --- /dev/null +++ b/src/include/mm_player_mused.h @@ -0,0 +1,84 @@ +/* + * libmm-player + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __MM_PLAYER_MUSED_H__ +#define __MM_PLAYER_MUSED_H__ + +/*=========================================================================================== +| | +| INCLUDE FILES | +| | +========================================================================================== */ +#include "mm_types.h" + +/*=========================================================================================== +| | +| GLOBAL DEFINITIONS AND DECLARATIONS FOR MODULE | +| | +========================================================================================== */ + +/*--------------------------------------------------------------------------- +| GLOBAL #defines: | +---------------------------------------------------------------------------*/ + +#ifdef __cplusplus + extern "C" { +#endif + +int mm_player_mused_create(MMHandleType *player); +int mm_player_mused_destroy(MMHandleType player); +int mm_player_mused_realize(MMHandleType player, char *caps); +int mm_player_mused_unrealize(MMHandleType player); +int mm_player_mused_pre_unrealize(MMHandleType player); + +/** + * This function get string of raw video caps. + * To be used by server. + * + * @param player [in] Handle of player. + * @param caps [out] String of caps. Should be freed after used. + * + * @return This function returns zero on success, or negative value with error + * code. + * @see + * @since + */ +int mm_player_get_raw_video_caps(MMHandleType player, char **caps); + +/** + * This function set "socket-path" element property of shmsink/src. + * To be used by both server and client. + * + * @param player [in] Handle of player. + * @param path [in] Local file path. + * + * @return This function returns zero on success, or negative value with error + * code. + * @see + * @since + */ +int mm_player_set_shm_stream_path(MMHandleType player, const char *path); + +#ifdef __cplusplus + } +#endif + +#endif /* __MM_PLAYER_MUSED_H__ */ diff --git a/src/include/mm_player_priv.h b/src/include/mm_player_priv.h old mode 100755 new mode 100644 index 9374fd2..0498d6f --- a/src/include/mm_player_priv.h +++ b/src/include/mm_player_priv.h @@ -845,11 +845,29 @@ void _mm_player_media_packet_video_stream_internal_buffer_unref(void *buffer); int _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel); int __mmplayer_gst_set_state (mm_player_t* player, GstElement * pipeline, GstState state, gboolean async, gint timeout ); int __mmplayer_set_state(mm_player_t* player, int state); -gboolean __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data); int __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command); gboolean __mmplayer_dump_pipeline_state( mm_player_t* player ); -GstBusSyncReply __mmplayer_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data); void __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id); +/* util */ +const gchar * __get_state_name ( int state ); +gboolean __is_streaming( mm_player_t* player ); +gboolean __is_rtsp_streaming( mm_player_t* player ); +gboolean __is_wfd_streaming( mm_player_t* player ); +gboolean __is_live_streaming ( mm_player_t* player ); +gboolean __is_http_streaming( mm_player_t* player ); +gboolean __is_http_live_streaming( mm_player_t* player ); +gboolean __is_dash_streaming( mm_player_t* player ); +gboolean __is_smooth_streaming( mm_player_t* player ); +gboolean __is_http_progressive_down(mm_player_t* player); + +gboolean __mmplayer_check_useful_message(mm_player_t *player, GstMessage * message); +gboolean __mmplayer_handle_gst_error ( mm_player_t* player, GstMessage * message, GError* error ); +gint __gst_handle_core_error( mm_player_t* player, int code ); +gint __gst_handle_library_error( mm_player_t* player, int code ); +gint __gst_handle_resource_error( mm_player_t* player, int code ); +gint __gst_handle_stream_error( mm_player_t* player, GError* error, GstMessage * message ); +int _mmplayer_set_shm_stream_path(MMHandleType hplayer, const char *path); +int _mmplayer_get_raw_video_caps(mm_player_t *player, char **caps); #ifdef __cplusplus } diff --git a/src/include/mused/mm_player_mused.h b/src/include/mused/mm_player_mused.h deleted file mode 100644 index 6cd83c5..0000000 --- a/src/include/mused/mm_player_mused.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * libmm-player - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef __MM_PLAYER_MUSED_H__ -#define __MM_PLAYER_MUSED_H__ - -/*=========================================================================================== -| | -| INCLUDE FILES | -| | -========================================================================================== */ -#include "mm_types.h" - -/*=========================================================================================== -| | -| GLOBAL DEFINITIONS AND DECLARATIONS FOR MODULE | -| | -========================================================================================== */ - -/*--------------------------------------------------------------------------- -| GLOBAL #defines: | ----------------------------------------------------------------------------*/ - -#ifdef __cplusplus - extern "C" { -#endif - -int mm_player_mused_create(MMHandleType *player); -int mm_player_mused_destroy(MMHandleType player); -int mm_player_mused_realize(MMHandleType player, char *caps); -int mm_player_mused_unrealize(MMHandleType player); -int mm_player_mused_pre_unrealize(MMHandleType player); - -/** - * This function get string of raw video caps. - * To be used by server. - * - * @param player [in] Handle of player. - * @param caps [out] String of caps. Should be freed after used. - * - * @return This function returns zero on success, or negative value with error - * code. - * @see - * @since - */ -int mm_player_get_raw_video_caps(MMHandleType player, char **caps); - -/** - * This function set "socket-path" element property of shmsink/src. - * To be used by both server and client. - * - * @param player [in] Handle of player. - * @param path [in] Local file path. - * - * @return This function returns zero on success, or negative value with error - * code. - * @see - * @since - */ -int mm_player_set_shm_stream_path(MMHandleType player, const char *path); - -#ifdef __cplusplus - } -#endif - -#endif /* __MM_PLAYER_MUSED_H__ */ diff --git a/src/mm_player.c b/src/mm_player.c deleted file mode 100755 index 8e8528a..0000000 --- a/src/mm_player.c +++ /dev/null @@ -1,1268 +0,0 @@ -/* - * libmm-player - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , YeJin Cho , - * Seungbae Shin , YoungHwan An - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include -#include - -#include -#include - -#include "mm_player.h" -#include "mm_player_priv.h" -#include "mm_player_attrs.h" -#include "mm_player_utils.h" -#include "mm_player_ini.h" -#include "mm_debug.h" -#include "mm_player_capture.h" -#include "mm_player_tracks.h" -#include "mm_player_es.h" - -int mm_player_create(MMHandleType *player) -{ - int result = MM_ERROR_NONE; - mm_player_t* new_player = NULL; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - - /* alloc player structure */ - new_player = g_malloc(sizeof(mm_player_t)); - if ( ! new_player ) - { - debug_error("Cannot allocate memory for player\n"); - goto ERROR; - } - memset(new_player, 0, sizeof(mm_player_t)); - - /* create player lock */ - g_mutex_init(&new_player->cmd_lock); - - /* create player lock */ - g_mutex_init(&new_player->playback_lock); - - - /* create msg callback lock */ - g_mutex_init(&new_player->msg_cb_lock); - - /* load ini files */ - result = mm_player_ini_load(&new_player->ini); - if(result != MM_ERROR_NONE) - { - debug_error("can't load ini"); - goto ERROR; - } - - result = mm_player_audio_effect_ini_load(&new_player->ini); - if(result != MM_ERROR_NONE) - { - debug_error("can't load audio ini"); - goto ERROR; - } - - - /* create player */ - result = _mmplayer_create_player((MMHandleType)new_player); - - if(result != MM_ERROR_NONE) - { - debug_error("failed to create player"); - goto ERROR; - } - - *player = (MMHandleType)new_player; - - return result; - -ERROR: - - if ( new_player ) - { - _mmplayer_destroy( (MMHandleType)new_player ); - g_mutex_clear(&new_player->cmd_lock); - g_mutex_clear(&new_player->playback_lock); - - MMPLAYER_FREEIF( new_player ); - } - - *player = (MMHandleType)0; - return MM_ERROR_PLAYER_NO_FREE_SPACE; // are you sure? -} - -int mm_player_destroy(MMHandleType player) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_destroy(player); - - MMPLAYER_CMD_UNLOCK( player ); - - g_mutex_clear(&((mm_player_t*)player)->cmd_lock); - g_mutex_clear(&((mm_player_t*)player)->playback_lock); - - memset( (mm_player_t*)player, 0x00, sizeof(mm_player_t) ); - - /* free player */ - g_free( (void*)player ); - - return result; -} - -int mm_player_realize(MMHandleType player) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_realize(player); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_unrealize(MMHandleType player) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_unrealize(player); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_message_callback(MMHandleType player, MMMessageCallback callback, void *user_param) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_message_callback(player, callback, user_param); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_pd_message_callback(MMHandleType player, MMMessageCallback callback, void *user_param) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - result = _mm_player_set_pd_downloader_message_cb(player, callback, user_param); - - return result; -} - -int mm_player_set_audio_stream_callback(MMHandleType player, mm_player_audio_stream_callback callback, void *user_param) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_audiostream_cb(player, callback, user_param); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_audio_stream_callback_ex(MMHandleType player, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_audiostream_cb_ex(player, sync, callback, user_param); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_video_stream_callback(MMHandleType player, mm_player_video_stream_callback callback, void *user_param) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_videostream_cb(player, callback, user_param); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_video_frame_render_error_callback(MMHandleType player, mm_player_video_frame_render_error_callback callback, void *user_param) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_videoframe_render_error_cb(player, callback, user_param); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_do_video_capture(MMHandleType player) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_do_video_capture(player); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_prepare_buffering_time(MMHandleType player, int second) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_prepare_buffering_time(player, second); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_runtime_buffering_mode(MMHandleType player, MMPlayerBufferingMode mode, int second) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_runtime_buffering_mode(player, mode, second); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_volume(MMHandleType player, MMPlayerVolumeType *volume) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(volume, MM_ERROR_INVALID_ARGUMENT); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_volume(player, *volume); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_get_volume(MMHandleType player, MMPlayerVolumeType *volume) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(volume, MM_ERROR_INVALID_ARGUMENT); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_get_volume(player, volume); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_mute(MMHandleType player, int mute) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_mute(player, mute); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_get_mute(MMHandleType player, int *mute) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(mute, MM_ERROR_INVALID_ARGUMENT); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_get_mute(player, mute); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_get_state(MMHandleType player, MMPlayerStateType *state) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(state, MM_ERROR_COMMON_INVALID_ARGUMENT); - - *state = MM_PLAYER_STATE_NULL; - - result = _mmplayer_get_state(player, (int*)state); - - return result; -} - -/* NOTE : It does not support some use cases, eg using colorspace converter */ -int mm_player_change_videosink(MMHandleType player, MMDisplaySurfaceType display_surface_type, void *display_overlay) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_change_videosink(player, display_surface_type, display_overlay); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_push_buffer(MMHandleType player, unsigned char *buf, int size) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - //MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_push_buffer(player, buf, size); - - //MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_start(MMHandleType player) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_start(player); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_stop(MMHandleType player) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_stop(player); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_pause(MMHandleType player) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_pause(player); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_resume(MMHandleType player) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_resume(player); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_activate_section_repeat(MMHandleType player, int start_pos, int end_pos) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_activate_section_repeat(player, start_pos, end_pos); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_deactivate_section_repeat(MMHandleType player) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_deactivate_section_repeat(player); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_gst_set_audio_channel(MMHandleType player, MMPlayerAudioChannel ch) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_gst_set_audio_channel(player, ch); - - MMPLAYER_CMD_UNLOCK( player ); - return result; -} - -int mm_player_set_play_speed(MMHandleType player, float rate) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_playspeed(player, rate); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_position(MMHandleType player, MMPlayerPosFormatType format, int pos) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - if (format >= MM_PLAYER_POS_FORMAT_NUM) - { - debug_error("wrong format\n"); - return MM_ERROR_COMMON_INVALID_ARGUMENT; - } - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_position(player, format, pos); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_get_position(MMHandleType player, MMPlayerPosFormatType format, int *pos) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(pos, MM_ERROR_COMMON_INVALID_ARGUMENT); - - if (format >= MM_PLAYER_POS_FORMAT_NUM) - { - debug_error("wrong format\n"); - return MM_ERROR_COMMON_INVALID_ARGUMENT; - } - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_get_position(player, (int)format, (unsigned long*)pos); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_get_buffer_position(MMHandleType player, MMPlayerPosFormatType format, int *start_pos, int *stop_pos) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(start_pos && stop_pos, MM_ERROR_COMMON_INVALID_ARGUMENT); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_get_buffer_position(player, (int)format, (unsigned long*)start_pos, (unsigned long*)stop_pos ); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_external_subtitle_path(MMHandleType player, const char* path) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_external_subtitle_path(player, path); - - MMPLAYER_CMD_UNLOCK( player ); - return result; -} - -int mm_player_adjust_subtitle_position(MMHandleType player, MMPlayerPosFormatType format, int pos) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - if (format >= MM_PLAYER_POS_FORMAT_NUM) - { - debug_error("wrong format(%d) \n", format); - return MM_ERROR_INVALID_ARGUMENT; - } - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_adjust_subtitle_postion(player, format, pos); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_adjust_video_position(MMHandleType player, int offset) -{ - int result = MM_ERROR_NONE; - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_adjust_video_postion(player, offset); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_subtitle_silent(MMHandleType player, int silent) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_subtitle_silent(player, silent); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_get_subtitle_silent(MMHandleType player, int* silent) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_get_subtitle_silent(player, silent); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_attribute(MMHandleType player, char **err_attr_name, const char *first_attribute_name, ...) -{ - int result = MM_ERROR_NONE; - va_list var_args; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(first_attribute_name, MM_ERROR_COMMON_INVALID_ARGUMENT); - - va_start (var_args, first_attribute_name); - result = _mmplayer_set_attribute(player, err_attr_name, first_attribute_name, var_args); - va_end (var_args); - - return result; -} - -int mm_player_get_attribute(MMHandleType player, char **err_attr_name, const char *first_attribute_name, ...) -{ - int result = MM_ERROR_NONE; - va_list var_args; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(first_attribute_name, MM_ERROR_COMMON_INVALID_ARGUMENT); - - va_start (var_args, first_attribute_name); - result = _mmplayer_get_attribute(player, err_attr_name, first_attribute_name, var_args); - va_end (var_args); - - return result; -} - -int mm_player_get_attribute_info(MMHandleType player, const char *attribute_name, MMPlayerAttrsInfo *info) -{ - int result = MM_ERROR_NONE; - - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(attribute_name, MM_ERROR_COMMON_INVALID_ARGUMENT); - return_val_if_fail(info, MM_ERROR_COMMON_INVALID_ARGUMENT); - - result = _mmplayer_get_attributes_info((MMHandleType)player, attribute_name, info); - - return result; -} - -int mm_player_get_pd_status(MMHandleType player, guint64 *current_pos, guint64 *total_size) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(current_pos, MM_ERROR_COMMON_INVALID_ARGUMENT); - return_val_if_fail(total_size, MM_ERROR_COMMON_INVALID_ARGUMENT); - - result = _mmplayer_get_pd_downloader_status(player, current_pos, total_size); - - return result; -} - -int mm_player_get_track_count(MMHandleType player, MMPlayerTrackType type, int *count) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(count, MM_ERROR_COMMON_INVALID_ARGUMENT); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_get_track_count(player, type, count); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_select_track(MMHandleType player, MMPlayerTrackType type, int index) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_select_track(player, type, index); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} -#ifdef _MULTI_TRACK -int mm_player_track_add_subtitle_language(MMHandleType player, int index) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_track_add_subtitle_language(player, index); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_track_remove_subtitle_language(MMHandleType player, int index) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_track_remove_subtitle_language(player, index); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; - -} -#endif -int mm_player_get_current_track(MMHandleType player, MMPlayerTrackType type, int *index) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(index, MM_ERROR_COMMON_INVALID_ARGUMENT); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_get_current_track(player, type, index); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_get_track_language_code(MMHandleType player, MMPlayerTrackType type, int index, char **code) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_get_track_language_code(player, type, index, code); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_display_zoom(MMHandleType player, float level, int x, int y) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_display_zoom(player, level, x, y); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_get_display_zoom(MMHandleType player, float *level, int *x, int *y) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(level, MM_ERROR_COMMON_INVALID_ARGUMENT); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_get_display_zoom(player, level, x, y); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - - -int mm_player_use_system_clock(MMHandleType player) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_use_system_clock(player); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_video_share_master_clock(MMHandleType player, - long long clock, - long long clock_delta, - long long video_time, - long long media_clock, - long long audio_time) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_video_share_master_clock(player, clock, clock_delta, video_time, media_clock, audio_time); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_get_video_share_master_clock(MMHandleType player, - long long *video_time, - long long *media_clock, - long long *audio_time) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT); - return_val_if_fail(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT); - return_val_if_fail(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_get_video_share_master_clock(player, video_time, media_clock, audio_time); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_get_video_rotate_angle(MMHandleType player, int *angle) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(angle, MM_ERROR_COMMON_INVALID_ARGUMENT); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_get_video_rotate_angle(player, angle); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_video_hub_download_mode(MMHandleType player, bool mode) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_video_hub_download_mode(player, mode); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_enable_sync_handler(MMHandleType player, bool enable) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_enable_sync_handler(player, enable); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_uri(MMHandleType player, const char *uri) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_uri(player, uri); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; - -} - -int mm_player_set_next_uri(MMHandleType player, const char *uri) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_next_uri(player, uri, FALSE); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; - -} - -int mm_player_get_next_uri(MMHandleType player, char **uri) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_get_next_uri(player, uri); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; - -} -#ifdef _MULTI_TRACK -int mm_player_track_foreach_selected_subtitle_language(MMHandleType player, mm_player_track_selected_subtitle_language_callback callback, void *user_param) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_track_foreach_selected_subtitle_language(player, callback, user_param); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} -#endif - -int mm_player_has_closed_caption(MMHandleType player, bool *exist) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(exist, MM_ERROR_INVALID_ARGUMENT); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_has_closed_caption(player, exist); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_enable_media_packet_video_stream(MMHandleType player, bool enable) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(enable, MM_ERROR_INVALID_ARGUMENT); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_enable_media_packet_video_stream(player, enable); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -void * mm_player_media_packet_video_stream_internal_buffer_ref(void *buffer) -{ - void * result; - result = _mm_player_media_packet_video_stream_internal_buffer_ref(buffer); - - return result; -} - -void mm_player_media_packet_video_stream_internal_buffer_unref(void *buffer) -{ - _mm_player_media_packet_video_stream_internal_buffer_unref(buffer); -} - -int mm_player_submit_packet(MMHandleType player, media_packet_h packet) -{ - - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - /* no lock here, otherwise callback for the "need-data" signal of appsrc will be blocking */ - //MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_submit_packet(player, packet); - - //MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_video_info (MMHandleType player, media_format_h format) -{ - int result = MM_ERROR_NONE; - - debug_log("\n"); - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_video_info(player, format); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; - -} - -int mm_player_set_audio_info (MMHandleType player, media_format_h format) -{ - int result = MM_ERROR_NONE; - - debug_log("\n"); - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_audio_info(player, format); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_subtitle_info (MMHandleType player, MMPlayerSubtitleStreamInfo *subtitle_stream_info) -{ - int result = MM_ERROR_NONE; - - debug_log("\n"); - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_subtitle_info(player, subtitle_stream_info); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_media_stream_buffer_max_size(MMHandleType player, MMPlayerStreamType type, unsigned long long max_size) -{ - int result = MM_ERROR_NONE; - - debug_log("\n"); - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_media_stream_max_size(player, type, max_size); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_get_media_stream_buffer_max_size(MMHandleType player, MMPlayerStreamType type, unsigned long long *max_size) -{ - int result = MM_ERROR_NONE; - guint64 _max_size = 0; - - debug_log("\n"); - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(max_size, MM_ERROR_INVALID_ARGUMENT); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_get_media_stream_max_size(player, type, &_max_size); - *max_size = _max_size; - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_media_stream_buffer_min_percent(MMHandleType player, MMPlayerStreamType type, unsigned min_percent) -{ - int result = MM_ERROR_NONE; - - debug_log("\n"); - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_media_stream_min_percent(player, type, min_percent); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_get_media_stream_buffer_min_percent(MMHandleType player, MMPlayerStreamType type, unsigned int *min_percent) -{ - int result = MM_ERROR_NONE; - - debug_log("\n"); - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(min_percent, MM_ERROR_INVALID_ARGUMENT); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_get_media_stream_min_percent(player, type, min_percent); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_media_stream_buffer_status_callback(MMHandleType player, MMPlayerStreamType type, mm_player_media_stream_buffer_status_callback callback, void * user_param) -{ - int result = MM_ERROR_NONE; - - debug_log("\n"); - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_media_stream_buffer_status_cb(player, type, callback, user_param); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_media_stream_seek_data_callback(MMHandleType player, MMPlayerStreamType type, mm_player_media_stream_seek_data_callback callback, void * user_param) -{ - int result = MM_ERROR_NONE; - - debug_log("\n"); - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_media_stream_seek_data_cb(player, type, callback, user_param); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_audio_stream_changed_callback(MMHandleType player, mm_player_stream_changed_callback callback, void *user_param) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_audiostream_changed_cb(player, callback, user_param); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_video_stream_changed_callback(MMHandleType player, mm_player_stream_changed_callback callback, void *user_param) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_videostream_changed_cb(player, callback, user_param); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -int mm_player_set_pcm_spec(MMHandleType player, int samplerate, int channel) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_pcm_spec(player, samplerate, channel); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} diff --git a/src/mm_player_audioeffect.c b/src/mm_player_audioeffect.c deleted file mode 100755 index ab90b2d..0000000 --- a/src/mm_player_audioeffect.c +++ /dev/null @@ -1,1087 +0,0 @@ -/* - * libmm-player - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi ,YeJin Cho , YoungHwan An - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -#include - -#include "mm_player_utils.h" -#include "mm_player_audioeffect.h" -#include "mm_player_ini.h" -#include "mm_player_priv.h" -#include - - -int -mm_player_get_foreach_present_supported_effect_type(MMHandleType hplayer, MMAudioEffectType effect_type, mmplayer_supported_audio_effect_cb foreach_cb, void *user_data) -{ - mm_player_t *player = NULL; - int result = MM_ERROR_NONE; - mm_sound_device_flags_e flags = MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG | MM_SOUND_DEVICE_STATE_ACTIVATED_FLAG; - MMSoundDeviceList_t device_list; - MMSoundDevice_t device_h = NULL; - mm_sound_device_type_e device_type; - int i = 0; - - MMPLAYER_FENTER(); - - return_val_if_fail ( hplayer, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - player = MM_PLAYER_CAST(hplayer); - - /* get status if speaker is activated */ - /* (1) get current device list */ - result = mm_sound_get_current_device_list(flags, &device_list); - - if ( result ) { - debug_error("mm_sound_get_current_device_list() failed [%x]!!", result); - MMPLAYER_FLEAVE(); - return result; - } - - /* (2) get device handle of device list */ - result = mm_sound_get_next_device (device_list, &device_h); - - if ( result ) { - debug_error("mm_sound_get_next_device() failed [%x]!!", result); - MMPLAYER_FLEAVE(); - return result; - } - - /* (3) get device type */ - result = mm_sound_get_device_type(device_h, &device_type); - - if ( result ) { - debug_error("mm_sound_get_device_type() failed [%x]!!", result); - MMPLAYER_FLEAVE(); - return result; - } - - /* preset */ - if (effect_type == MM_AUDIO_EFFECT_TYPE_PRESET) - { - for ( i = 0; i < MM_AUDIO_EFFECT_PRESET_NUM; i++ ) - { - if (player->ini.audio_effect_preset_list[i] ) - { - if (device_type == MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER && - player->ini.audio_effect_preset_earphone_only_list[i]) - { - continue; - } - if (!foreach_cb(effect_type,i, user_data)) - { - goto CALLBACK_ERROR; - } - } - } - } - /* custom */ - else if (effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) - { - for ( i = 0; i < MM_AUDIO_EFFECT_CUSTOM_NUM; i++ ) - { - if (player->ini.audio_effect_custom_list[i] ) - { - if (device_type == MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER && - player->ini.audio_effect_custom_earphone_only_list[i]) - { - continue; - } - if (!foreach_cb(effect_type,i, user_data)) - { - goto CALLBACK_ERROR; - } - } - } - } - else - { - debug_error("invalid effect type(%d)", effect_type); - result = MM_ERROR_INVALID_ARGUMENT; - } - - MMPLAYER_FLEAVE(); - - return result; - -CALLBACK_ERROR: - debug_error("foreach callback returned error"); - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_INTERNAL; -} - - -int -__mmplayer_set_harmony_effect(mm_player_t *player, GstElement *audio_effect_element) -{ - gint *ext_effect_level_list = NULL; - int count = 1; /* start from 1, because of excepting eq index */ - int ext_level_index = 0; - int result = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - return_val_if_fail ( audio_effect_element, MM_ERROR_INVALID_ARGUMENT ); - - /* Custom EQ */ - if( player->ini.audio_effect_custom_eq_band_num ) - { - debug_log("pass custom EQ level list to audio effect plugin"); - /* set custom-equalizer level list */ - g_object_set(audio_effect_element, "custom-eq", player->audio_effect_info.custom_eq_level, NULL); - } - else - { - debug_warning("no custom EQ"); - } - - /* Custom Extension effects */ - if( player->ini.audio_effect_custom_ext_num ) - { - debug_log("pass custom extension level list to audio effect plugin"); - ext_effect_level_list = player->audio_effect_info.custom_ext_level_for_plugin; - if (!ext_effect_level_list) { - ext_effect_level_list = (gint*) malloc (sizeof(gint)*player->ini.audio_effect_custom_ext_num); - if (!ext_effect_level_list) - { - debug_error("memory allocation for extension effect list failed"); - return MM_ERROR_OUT_OF_MEMORY; - } - else - { - memset (ext_effect_level_list, 0, player->ini.audio_effect_custom_ext_num); - - /* associate it to player handle */ - player->audio_effect_info.custom_ext_level_for_plugin = ext_effect_level_list; - } - } - - while ( count < MM_AUDIO_EFFECT_CUSTOM_NUM ) - { - if ( player->ini.audio_effect_custom_list[count] ) - { - ext_effect_level_list[ext_level_index] = player->audio_effect_info.custom_ext_level[count-1]; - ext_level_index++; - if (ext_level_index == player->ini.audio_effect_custom_ext_num) - { - break; - } - } - count++; - } - - /* set custom-extension effects level list */ - g_object_set(audio_effect_element, "custom-ext", ext_effect_level_list, NULL); - } - else - { - debug_warning("no custom extension effect"); - } - - /* order action to audio effect plugin */ - g_object_set(audio_effect_element, "filter-action", MM_AUDIO_EFFECT_TYPE_CUSTOM, NULL); - debug_log("filter-action = %d", MM_AUDIO_EFFECT_TYPE_CUSTOM); - - MMPLAYER_FLEAVE(); - - return result; -} - - -gboolean -__mmplayer_is_earphone_only_effect_type(mm_player_t *player, MMAudioEffectType effect_type, int effect) -{ - gboolean result = FALSE; - int i = 0; - - MMPLAYER_FENTER(); - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - /* preset */ - if (effect_type == MM_AUDIO_EFFECT_TYPE_PRESET) - { - if (player->ini.audio_effect_preset_earphone_only_list[effect]) - { - debug_msg("this preset effect(%d) is only available with earphone", effect); - result = TRUE; - } - } - /* custom */ - else if (effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) - { - for (i = 1; i < MM_AUDIO_EFFECT_CUSTOM_NUM; i++) /* it starts from 1(except testing for EQ) */ - { - if (player->ini.audio_effect_custom_earphone_only_list[i]) - { - /* check if the earphone only custom effect was set */ - if (player->audio_effect_info.custom_ext_level[i-1]) - { - debug_msg("this custom effect(%d) is only available with earphone", i); - result = TRUE; - } - } - } - } - else - { - debug_error("invalid effect type(%d)", effect_type); - } - - MMPLAYER_FLEAVE(); - - return result; -} - -int -__mmplayer_audio_set_output_type (mm_player_t *player, MMAudioEffectType effect_type, int effect) -{ - GstElement *audio_effect_element = NULL; - mm_sound_device_flags_e flags = MM_SOUND_DEVICE_ALL_FLAG; - MMSoundDeviceList_t device_list; - MMSoundDevice_t device_h = NULL; - mm_sound_device_type_e device_type; - int output_type = 0; - int result = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - audio_effect_element = player->pipeline->audiobin[MMPLAYER_A_FILTER].gst; - - /* (1) get current device list */ - result = mm_sound_get_current_device_list(flags, &device_list); - - if ( result ) { - debug_error("mm_sound_get_current_device_list() failed [%x]!!", result); - MMPLAYER_FLEAVE(); - return result; - } - - /* (2) get device handle of device list */ - result = mm_sound_get_next_device (device_list, &device_h); - - if ( result ) { - debug_error("mm_sound_get_next_device() failed [%x]!!", result); - MMPLAYER_FLEAVE(); - return result; - } - - /* (3) get device type */ - result = mm_sound_get_device_type(device_h, &device_type); - - if ( result ) { - debug_error("mm_sound_get_device_type() failed [%x]!!", result); - MMPLAYER_FLEAVE(); - return result; - } - - /* SPEAKER case */ - if (device_type == MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER) - { - if ( MM_AUDIO_EFFECT_TYPE_SQUARE != effect_type ) { - if (__mmplayer_is_earphone_only_effect_type(player, effect_type, effect)) - { - debug_error("earphone is not equipped, this filter will not be applied"); - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_SOUND_EFFECT_INVALID_STATUS; - } - } - - output_type = MM_AUDIO_EFFECT_OUTPUT_SPK; - } - else if (device_type == MM_SOUND_DEVICE_TYPE_MIRRORING) - { - output_type = MM_AUDIO_EFFECT_OUTPUT_OTHERS; - } - else if (device_type == MM_SOUND_DEVICE_TYPE_HDMI) - { - output_type = MM_AUDIO_EFFECT_OUTPUT_HDMI; - } - else if (device_type == MM_SOUND_DEVICE_TYPE_BLUETOOTH) - { - output_type = MM_AUDIO_EFFECT_OUTPUT_BT; - } - else if (device_type == MM_SOUND_DEVICE_TYPE_USB_AUDIO) - { - output_type = MM_AUDIO_EFFECT_OUTPUT_USB_AUDIO; - } - /* Other case, include WIRED_ACCESSORY */ - else - { - output_type = MM_AUDIO_EFFECT_OUTPUT_EAR; - } - debug_warning("output_type = %d (0:spk,1:ear,2:others)", output_type); - - /* set filter output mode */ - g_object_set(audio_effect_element, "filter-output-mode", output_type, NULL); - - return result; -} - -gboolean -_mmplayer_is_supported_effect_type(mm_player_t* player, MMAudioEffectType effect_type, int effect) -{ - gboolean result = TRUE; - mm_sound_device_flags_e flags = MM_SOUND_DEVICE_ALL_FLAG; - MMSoundDeviceList_t device_list; - MMSoundDevice_t device_h = NULL; - mm_sound_device_type_e device_type; - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - /* get status if speaker is activated */ - /* (1) get current device list */ - ret = mm_sound_get_current_device_list(flags, &device_list); - if (ret) { - MMPLAYER_FLEAVE(); - debug_error("mm_sound_get_current_device_list() failed [%x]!!", ret); - return FALSE; - } - - /* (2) get device handle of device list */ - ret = mm_sound_get_next_device (device_list, &device_h); - - if (ret) { - debug_error("mm_sound_get_next_device() failed [%x]!!", ret); - MMPLAYER_FLEAVE(); - return FALSE; - } - - /* (3) get device type */ - ret = mm_sound_get_device_type(device_h, &device_type); - - if (ret) { - debug_error("mm_sound_get_device_type() failed [%x]!!", ret); - MMPLAYER_FLEAVE(); - return FALSE; - } - - /* preset */ - if (effect_type == MM_AUDIO_EFFECT_TYPE_PRESET) - { - if ( effect < MM_AUDIO_EFFECT_PRESET_AUTO || effect >= MM_AUDIO_EFFECT_PRESET_NUM ) - { - debug_error("out of range, preset effect(%d)", effect); - result = FALSE; - } - else - { - if (!player->ini.audio_effect_preset_list[effect]) - { - debug_error("this effect(%d) is not supported", effect); - result = FALSE; - } - else - { - if (device_type == MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER && - player->ini.audio_effect_preset_earphone_only_list[effect]) - { - result = FALSE; - } - } - } - } - /* custom */ - else if (effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) - { - if ( effect < MM_AUDIO_EFFECT_CUSTOM_EQ || effect >= MM_AUDIO_EFFECT_CUSTOM_NUM ) - { - debug_error("out of range, custom effect(%d)", effect); - result = FALSE; - } - else - { - if (!player->ini.audio_effect_custom_list[effect]) - { - debug_error("this custom effect(%d) is not supported", effect); - result = FALSE; - } - else - { - if (device_type == MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER && - player->ini.audio_effect_custom_earphone_only_list[effect]) - { - result = FALSE; - } - } - } - } - else if (effect_type == MM_AUDIO_EFFECT_TYPE_SQUARE) - { - if (!player->ini.use_audio_effect_custom) - { - debug_error("Square effect is not supported"); - result = FALSE; - } - } - else - { - debug_error("invalid effect type(%d)", effect_type); - result = FALSE; - } - - - MMPLAYER_FLEAVE(); - - return result; -} - -int -_mmplayer_audio_effect_custom_apply(mm_player_t *player) -{ - GstElement *audio_effect_element = NULL; - int result = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - /* Music Player can set audio effect value before Audiobin is created. */ - if ( !player->pipeline || !player->pipeline->audiobin || !player->pipeline->audiobin[MMPLAYER_A_FILTER].gst ) - { - debug_warning("effect element is not created yet."); - - player->bypass_audio_effect = FALSE; - - /* store audio effect setting in order to apply it when audio effect plugin is created */ - player->audio_effect_info.effect_type = MM_AUDIO_EFFECT_TYPE_CUSTOM; - } - else - { - audio_effect_element = player->pipeline->audiobin[MMPLAYER_A_FILTER].gst; - - /* get status if speaker is activated */ - result = __mmplayer_audio_set_output_type(player, MM_AUDIO_EFFECT_TYPE_CUSTOM, 0); - - if ( result != MM_ERROR_NONE) { - debug_error("failed to set output mode"); - MMPLAYER_FLEAVE(); - return result; - } - - result = __mmplayer_set_harmony_effect(player, audio_effect_element); - if ( result ) - { - debug_error("_set_harmony_effect() failed(%x)", result); - MMPLAYER_FLEAVE(); - return result; - } - } - player->set_mode.rich_audio = TRUE; - - MMPLAYER_FLEAVE(); - - return result; -} - -int -_mmplayer_audio_effect_custom_update_level(mm_player_t *player) -{ - GstElement *audio_effect_element = NULL; - int result = MM_ERROR_NONE; - int ext_level_index = 0; - int count = 1; - int i = 0; - gint *custom_eq = NULL; - gint *custom_ext_effect_level_list = NULL; - - MMPLAYER_FENTER(); - - return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - audio_effect_element = player->pipeline->audiobin[MMPLAYER_A_FILTER].gst; - - /* get custom eq effect */ - g_object_get(audio_effect_element, "custom-eq", &custom_eq, NULL); - - memcpy(player->audio_effect_info.custom_eq_level, custom_eq, sizeof(gint) * player->ini.audio_effect_custom_eq_band_num); - - for (i=0; iini.audio_effect_custom_eq_band_num;i++) - { - debug_log("updated custom-eq [%d] = %d", i, player->audio_effect_info.custom_eq_level[i]); - } - - /* get custom ext effect */ - - g_object_get(audio_effect_element, "custom-ext", &custom_ext_effect_level_list, NULL); - - while ( count < MM_AUDIO_EFFECT_CUSTOM_NUM ) - { - if ( player->ini.audio_effect_custom_list[count] ) - { - player->audio_effect_info.custom_ext_level[count-1] - = custom_ext_effect_level_list[ext_level_index]; - debug_log("updated custom-ext [%d] = %d", count, player->audio_effect_info.custom_ext_level[count-1]); - ext_level_index++; - } - count++; - } - - - MMPLAYER_FLEAVE(); - return result; -} - - -int -mm_player_audio_effect_custom_clear_eq_all(MMHandleType hplayer) -{ - int result = MM_ERROR_NONE; - mm_player_t* player = (mm_player_t*)hplayer; - - MMPLAYER_FENTER(); - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - /* clear EQ custom effect */ - memset(player->audio_effect_info.custom_eq_level, MM_AUDIO_EFFECT_CUSTOM_LEVEL_INIT, sizeof(int)*MM_AUDIO_EFFECT_EQ_BAND_NUM_MAX); - - debug_msg("All the EQ bands clearing success"); - - MMPLAYER_FLEAVE(); - - return result; -} - - -int -mm_player_audio_effect_custom_clear_ext_all(MMHandleType hplayer) -{ - int i; - int result = MM_ERROR_NONE; - mm_player_t* player = (mm_player_t*)hplayer; - - MMPLAYER_FENTER(); - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - /* clear ALL custom effects, except EQ */ - for ( i = 0 ; i < MM_AUDIO_EFFECT_CUSTOM_NUM - 1 ; i++ ) - { - player->audio_effect_info.custom_ext_level[i] = MM_AUDIO_EFFECT_CUSTOM_LEVEL_INIT; - } - - debug_msg("All the extension effects clearing success"); - - MMPLAYER_FLEAVE(); - - return result; -} - - -int -mm_player_is_supported_preset_effect_type(MMHandleType hplayer, MMAudioEffectPresetType effect) -{ - mm_player_t* player = (mm_player_t*)hplayer; - int result = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_PRESET, effect ) ) - { - result = MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; - } - - MMPLAYER_FLEAVE(); - - return result; -} - - -int -mm_player_is_supported_custom_effect_type(MMHandleType hplayer, MMAudioEffectCustomType effect) -{ - mm_player_t* player = (mm_player_t*)hplayer; - int result = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_CUSTOM, effect ) ) - { - result = MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; - } - - MMPLAYER_FLEAVE(); - - return result; -} - -int -mm_player_audio_effect_custom_apply(MMHandleType hplayer) -{ - mm_player_t* player = (mm_player_t*)hplayer; - int result = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - if (!player->ini.use_audio_effect_custom) - { - debug_error("audio effect(custom) is not supported"); - MMPLAYER_FLEAVE(); - return MM_ERROR_NOT_SUPPORT_API; - } - - result = _mmplayer_audio_effect_custom_apply(player); - - MMPLAYER_FLEAVE(); - - return result; -} - - -int -mm_player_audio_effect_bypass (MMHandleType hplayer) -{ - mm_player_t* player = (mm_player_t*)hplayer; - int result = MM_ERROR_NONE; - GstElement *audio_effect_element = NULL; - - MMPLAYER_FENTER(); - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - if ( !player->ini.use_audio_effect_preset && !player->ini.use_audio_effect_custom ) - { - debug_error("audio effect(preset/custom) is not supported"); - MMPLAYER_FLEAVE(); - return MM_ERROR_NOT_SUPPORT_API; - } - if ( !player->pipeline || !player->pipeline->audiobin || !player->pipeline->audiobin[MMPLAYER_A_FILTER].gst ) - { - debug_warning("effect element is not created yet."); - } - else - { - audio_effect_element = player->pipeline->audiobin[MMPLAYER_A_FILTER].gst; - - /* order action to audio effect plugin */ - g_object_set(audio_effect_element, "filter-action", MM_AUDIO_EFFECT_TYPE_NONE, NULL); - debug_log("filter-action = %d", MM_AUDIO_EFFECT_TYPE_NONE); - } - - MMPLAYER_FLEAVE(); - - return result; -} - - -int -_mmplayer_audio_effect_custom_set_level_ext(mm_player_t *player, MMAudioEffectCustomType custom_effect_type, int level) -{ - int effect_level_max = 0; - int effect_level_min = 0; - int count = 1; /* start from 1, because of excepting eq index */ - int ext_level_index = 1; /* start from 1, because of excepting eq index */ - int result = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - /* check if EQ is supported */ - if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_CUSTOM, custom_effect_type ) ) - { - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; - } - - while ( count < MM_AUDIO_EFFECT_CUSTOM_NUM ) - { - if ( player->ini.audio_effect_custom_list[count] ) - { - if ( count == custom_effect_type ) - { - effect_level_min = player->ini.audio_effect_custom_min_level_list[ext_level_index]; - effect_level_max = player->ini.audio_effect_custom_max_level_list[ext_level_index]; - debug_msg("level min value(%d), level max value(%d)", effect_level_min, effect_level_max); - break; - } - ext_level_index++; - if (ext_level_index == player->ini.audio_effect_custom_ext_num + 1) - { - debug_error("could not find min, max value. maybe effect information in ini file is not proper for audio effect plugin"); - break; - } - } - count++; - } - - if ( level < effect_level_min || level > effect_level_max ) - { - debug_error("out of range, level(%d)", level); - result = MM_ERROR_INVALID_ARGUMENT; - } - else - { - player->audio_effect_info.custom_ext_level[custom_effect_type-1] = level; - debug_msg("set ext[%d] = %d", custom_effect_type-1, level); - } - - MMPLAYER_FLEAVE(); - - return result; -} - - -int -_mmplayer_audio_effect_custom_set_level_eq(mm_player_t *player, int index, int level) -{ - gint eq_level_max = 0; - gint eq_level_min = 0; - int result = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - /* check if EQ is supported */ - if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_CUSTOM, MM_AUDIO_EFFECT_CUSTOM_EQ ) ) - { - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; - } - - if ( index < 0 || index > player->ini.audio_effect_custom_eq_band_num - 1 ) - { - debug_error("out of range, index(%d)", index); - result = MM_ERROR_INVALID_ARGUMENT; - } - else - { - eq_level_min = player->ini.audio_effect_custom_min_level_list[MM_AUDIO_EFFECT_CUSTOM_EQ]; - eq_level_max = player->ini.audio_effect_custom_max_level_list[MM_AUDIO_EFFECT_CUSTOM_EQ]; - debug_msg("EQ level min value(%d), EQ level max value(%d)", eq_level_min, eq_level_max); - - if ( level < eq_level_min || level > eq_level_max ) - { - debug_error("out of range, EQ level(%d)", level); - result = MM_ERROR_INVALID_ARGUMENT; - } - else - { - player->audio_effect_info.custom_eq_level[index] = level; - debug_msg("set EQ[%d] = %d", index, level); - } - } - - MMPLAYER_FLEAVE(); - - return result; -} - - -/* NOTE : parameter eq_index is only used for _set_eq_level() */ -int -mm_player_audio_effect_custom_set_level(MMHandleType hplayer, MMAudioEffectCustomType effect_custom_type, int eq_index, int level) -{ - mm_player_t* player = (mm_player_t*)hplayer; - int result = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - /* check if this effect type is supported */ - if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_CUSTOM, effect_custom_type ) ) - { - result = MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; - } - else - { - if (effect_custom_type == MM_AUDIO_EFFECT_CUSTOM_EQ) - { - result = _mmplayer_audio_effect_custom_set_level_eq(player, eq_index, level); - } - else if (effect_custom_type > MM_AUDIO_EFFECT_CUSTOM_EQ && effect_custom_type < MM_AUDIO_EFFECT_CUSTOM_NUM) - { - result = _mmplayer_audio_effect_custom_set_level_ext(player, effect_custom_type, level); - } - else - { - debug_error("out of range, effect type(%d)", effect_custom_type); - result = MM_ERROR_INVALID_ARGUMENT; - } - } - - MMPLAYER_FLEAVE(); - - return result; -} - - -int -mm_player_audio_effect_custom_get_eq_bands_number(MMHandleType hplayer, int *bands) -{ - mm_player_t* player = (mm_player_t*)hplayer; - int result = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - /* check if EQ is supported */ - if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_CUSTOM, MM_AUDIO_EFFECT_CUSTOM_EQ ) ) - { - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; - } - - *bands = player->ini.audio_effect_custom_eq_band_num; - debug_log("number of custom EQ band = %d", *bands); - - MMPLAYER_FLEAVE(); - - return result; -} - - -int -mm_player_audio_effect_custom_get_eq_bands_width(MMHandleType hplayer, int band_idx, int *width) -{ - mm_player_t* player = (mm_player_t*)hplayer; - int result = MM_ERROR_NONE; - unsigned int eq_num = 0; - - MMPLAYER_FENTER(); - - return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - /* check if EQ is supported */ - if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_CUSTOM, MM_AUDIO_EFFECT_CUSTOM_EQ ) ) - { - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; - } - - eq_num = player->ini.audio_effect_custom_eq_band_num; - if (band_idx < 0 || band_idx > eq_num-1) - { - debug_error("out of range, invalid band_idx(%d)", band_idx); - result = MM_ERROR_INVALID_ARGUMENT; - } - else - { - /* set the width of EQ band */ - *width = player->ini.audio_effect_custom_eq_band_width[band_idx]; - debug_log("width of band_idx(%d) = %dHz", band_idx, *width); - } - - MMPLAYER_FLEAVE(); - - return result; -} - - -int -mm_player_audio_effect_custom_get_eq_bands_freq(MMHandleType hplayer, int band_idx, int *freq) -{ - mm_player_t* player = (mm_player_t*)hplayer; - int result = MM_ERROR_NONE; - unsigned int eq_num = 0; - - MMPLAYER_FENTER(); - - return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - /* check if EQ is supported */ - if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_CUSTOM, MM_AUDIO_EFFECT_CUSTOM_EQ ) ) - { - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; - } - - eq_num = player->ini.audio_effect_custom_eq_band_num; - if (band_idx < 0 || band_idx > eq_num-1) - { - debug_error("out of range, invalid band_idx(%d)", band_idx); - result = MM_ERROR_INVALID_ARGUMENT; - } - else - { - /* set the frequency of EQ band */ - *freq = player->ini.audio_effect_custom_eq_band_freq[band_idx]; - debug_log("frequency of band_idx(%d) = %dHz", band_idx, *freq); - } - - MMPLAYER_FLEAVE(); - - return result; -} - - -int -mm_player_audio_effect_custom_get_level(MMHandleType hplayer, MMAudioEffectCustomType type, int eq_index, int *level) -{ - mm_player_t* player = (mm_player_t*)hplayer; - int result = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - return_val_if_fail( level, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - /* check if this effect type is supported */ - if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_CUSTOM, type ) ) - { - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; - } - - if (type == MM_AUDIO_EFFECT_CUSTOM_EQ) - { - if ( eq_index < 0 || eq_index > player->ini.audio_effect_custom_eq_band_num - 1 ) - { - debug_error("out of range, EQ index(%d)", eq_index); - result = MM_ERROR_INVALID_ARGUMENT; - } - else - { - *level = player->audio_effect_info.custom_eq_level[eq_index]; - debug_log("EQ index = %d, level = %d", eq_index, *level); - } - } - else if ( type > MM_AUDIO_EFFECT_CUSTOM_EQ && type < MM_AUDIO_EFFECT_CUSTOM_NUM ) - { - *level = player->audio_effect_info.custom_ext_level[type-1]; - debug_log("extension effect index = %d, level = %d", type, *level); - } - else - { - debug_error("out of range, type(%d)", type); - result = MM_ERROR_INVALID_ARGUMENT; - } - - MMPLAYER_FLEAVE(); - - return result; -} - - -int -mm_player_audio_effect_custom_get_level_range(MMHandleType hplayer, MMAudioEffectCustomType type, int *min, int *max) -{ - mm_player_t* player = (mm_player_t*)hplayer; - int result = MM_ERROR_NONE; - int count = 1; /* start from 1, because of excepting eq index */ - int ext_level_index = 1; /* start from 1, because of excepting eq index */ - - MMPLAYER_FENTER(); - - return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - return_val_if_fail( min, MM_ERROR_PLAYER_NOT_INITIALIZED ); - return_val_if_fail( max, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - /* check if this effect type is supported */ - if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_CUSTOM, type ) ) - { - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; - } - - if ( type == MM_AUDIO_EFFECT_CUSTOM_EQ ) - { - *min = player->ini.audio_effect_custom_min_level_list[MM_AUDIO_EFFECT_CUSTOM_EQ]; - *max = player->ini.audio_effect_custom_max_level_list[MM_AUDIO_EFFECT_CUSTOM_EQ]; - debug_log("EQ min level = %d, max level = %d", *min, *max); - } - else - { - while ( count < MM_AUDIO_EFFECT_CUSTOM_NUM ) - { - if ( player->ini.audio_effect_custom_list[count] ) - { - if ( count == type ) - { - *min = player->ini.audio_effect_custom_min_level_list[ext_level_index]; - *max = player->ini.audio_effect_custom_max_level_list[ext_level_index]; - debug_msg("Extension effect(%d) min level = %d, max level = %d", count, *min, *max); - break; - } - ext_level_index++; - if ( ext_level_index == player->ini.audio_effect_custom_ext_num + 1 ) - { - debug_error("could not find min, max value. maybe effect information in ini file is not proper for audio effect plugin"); - break; - } - } - count++; - } - } - - MMPLAYER_FLEAVE(); - - return result; -} - - -int -mm_player_audio_effect_custom_set_level_eq_from_list(MMHandleType hplayer, int *level_list, int size) -{ - mm_player_t *player = (mm_player_t*)hplayer; - gint i = 0; - gint eq_level_min = 0; - gint eq_level_max = 0; - int result = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - /* check if EQ is supported */ - if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_CUSTOM, MM_AUDIO_EFFECT_CUSTOM_EQ ) ) - { - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; - } - - if ( size != player->ini.audio_effect_custom_eq_band_num ) - { - debug_error("input size variable(%d) does not match with number of eq band(%d)", size, player->ini.audio_effect_custom_eq_band_num); - result = MM_ERROR_INVALID_ARGUMENT; - } - else - { - eq_level_min = player->ini.audio_effect_custom_min_level_list[MM_AUDIO_EFFECT_CUSTOM_EQ]; - eq_level_max = player->ini.audio_effect_custom_max_level_list[MM_AUDIO_EFFECT_CUSTOM_EQ]; - - for ( i = 0 ; i < size ; i++ ) - { - if ( level_list[i] < eq_level_min || level_list[i] > eq_level_max) - { - debug_error("out of range, level[%d]=%d", i, level_list[i]); - result = MM_ERROR_INVALID_ARGUMENT; - break; - } - player->audio_effect_info.custom_eq_level[i] = level_list[i]; - } - } - MMPLAYER_FLEAVE(); - - return result; -} diff --git a/src/mm_player_capture.c b/src/mm_player_capture.c deleted file mode 100755 index 1526cff..0000000 --- a/src/mm_player_capture.c +++ /dev/null @@ -1,954 +0,0 @@ -/* - * libmm-player - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , YeJin Cho , - * Seungbae Shin , YoungHwan An - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/*=========================================================================================== -| | -| INCLUDE FILES | -| | -========================================================================================== */ -#include "mm_player_utils.h" -#include "mm_player_capture.h" -#include "mm_player_priv.h" -#include "mm_player_utils.h" - -#include -#include - -/*--------------------------------------------------------------------------- -| LOCAL VARIABLE DEFINITIONS for internal | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| LOCAL FUNCTION PROTOTYPES: | ----------------------------------------------------------------------------*/ -static GstPadProbeReturn __mmplayer_video_capture_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data); -static int __mmplayer_get_video_frame_from_buffer(mm_player_t* player, GstPad *pad, GstBuffer *buffer); -static gpointer __mmplayer_capture_thread(gpointer data); -static void __csc_tiled_to_linear_crop(unsigned char *yuv420_dest, unsigned char *nv12t_src, int yuv420_width, int yuv420_height, int left, int top, int right, int buttom); -static int __tile_4x2_read(int x_size, int y_size, int x_pos, int y_pos); -static int __mm_player_convert_colorspace(mm_player_t* player, unsigned char* src_data, mm_util_img_format src_fmt, unsigned int src_w, unsigned int src_h, mm_util_img_format dst_fmt); - -/*=========================================================================================== -| | -| FUNCTION DEFINITIONS | -| | -========================================================================================== */ -int -_mmplayer_initialize_video_capture(mm_player_t* player) -{ - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - /* create capture mutex */ - g_mutex_init(&player->capture_thread_mutex); - - /* create capture cond */ - g_cond_init(&player->capture_thread_cond); - - - player->capture_thread_exit = FALSE; - - /* create video capture thread */ - player->capture_thread = - g_thread_try_new ("capture_thread",__mmplayer_capture_thread, (gpointer)player, NULL); - - if ( ! player->capture_thread ) - { - goto ERROR; - } - - return MM_ERROR_NONE; - -ERROR: - /* capture thread */ - g_mutex_clear(&player->capture_thread_mutex ); - - g_cond_clear (&player->capture_thread_cond ); - - return MM_ERROR_PLAYER_INTERNAL; -} - -int -_mmplayer_release_video_capture(mm_player_t* player) -{ - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - /* release capture thread */ - g_mutex_lock(&player->capture_thread_mutex); - player->capture_thread_exit = TRUE; - g_cond_signal( &player->capture_thread_cond ); - g_mutex_unlock(&player->capture_thread_mutex); - - debug_log("waitting for capture thread exit"); - g_thread_join ( player->capture_thread ); - g_mutex_clear(&player->capture_thread_mutex ); - g_cond_clear(&player->capture_thread_cond ); - debug_log("capture thread released"); - - return MM_ERROR_NONE; -} - -int -_mmplayer_do_video_capture(MMHandleType hplayer) -{ - mm_player_t* player = (mm_player_t*) hplayer; - int ret = MM_ERROR_NONE; - GstPad *pad = NULL; - - MMPLAYER_FENTER(); - - return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - - /* capturing or not */ - if (player->video_capture_cb_probe_id || player->capture.data - || player->captured.data[0] || player->captured.data[1] - ) - { - debug_warning("capturing... we can't do any more"); - return MM_ERROR_PLAYER_INVALID_STATE; - } - - /* check if video pipeline is linked or not */ - if (!player->pipeline->videobin) - { - debug_warning("not ready to capture"); - return MM_ERROR_PLAYER_INVALID_STATE; - } - - /* check if drm file */ - if (player->is_drm_file) - { - debug_warning("not supported in drm file"); - return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION; - } - - pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink" ); - - if (player->state != MM_PLAYER_STATE_PLAYING) - { - if (player->state == MM_PLAYER_STATE_PAUSED) // get last buffer from video sink - { - GstSample *sample = NULL; - - gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, 5 * GST_SECOND); //5 seconds - - g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "last-sample", &sample, NULL); - - if (sample) - { - GstBuffer *buf = NULL; - buf = gst_sample_get_buffer(sample); - - if (buf) - { - ret = __mmplayer_get_video_frame_from_buffer(player, pad, buf); - } - else - { - debug_warning("failed to get video frame"); - } - gst_sample_unref(sample); - } - return ret; - } - else - { - debug_warning("invalid state(%d) to capture", player->state); - return MM_ERROR_PLAYER_INVALID_STATE; - } - } - - /* register probe */ - player->video_capture_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER, - __mmplayer_video_capture_probe, player, NULL); - - gst_object_unref(GST_OBJECT(pad)); - pad = NULL; - - MMPLAYER_FLEAVE(); - - return ret; -} - -int -__mmplayer_handle_orientation (mm_player_t* player, int orientation, int format) -{ - unsigned char *src_buffer = NULL; - int ret = MM_ERROR_NONE; - unsigned char *dst_frame = NULL; - unsigned int dst_width = 0; - unsigned int dst_height = 0; - unsigned int dst_size = 0; - mm_util_img_rotate_type rot_enum = MM_UTIL_ROTATE_NUM; - - player->capture.orientation = orientation; - - if (orientation == 90 || orientation == 270) - { - dst_width = player->captured.height[0]; - dst_height = player->captured.width[0]; - debug_log ("interchange width & height"); - } - else if (orientation == 180) - { - dst_width = player->captured.width[0]; - dst_height = player->captured.height[0]; - } - else if (orientation == 0) - { - debug_error ("no need handle orientation : %d", orientation); - player->capture.width = player->captured.width[0]; - player->capture.height = player->captured.height[0]; - return MM_ERROR_NONE; - } - else - { - debug_error ("wrong orientation value..."); - } - - /* height & width will be interchanged for 90 and 270 orientation */ - ret = mm_util_get_image_size(format, dst_width, dst_height, &dst_size); - if (ret != MM_ERROR_NONE) - { - debug_error("failed to get destination frame size"); - return ret; - } - - debug_log ("before rotation : dst_width = %d and dst_height = %d", dst_width, dst_height); - - dst_frame = (unsigned char*) malloc (dst_size); - if (!dst_frame) - { - debug_error("failed to allocate memory"); - return MM_ERROR_PLAYER_NO_FREE_SPACE; - } - - src_buffer = (unsigned char*)player->capture.data; - - /* convert orientation degree into enum here */ - switch(orientation) - { - case 0: - rot_enum = MM_UTIL_ROTATE_0; - break; - case 90: - rot_enum = MM_UTIL_ROTATE_90; - break; - case 180: - rot_enum = MM_UTIL_ROTATE_180; - break; - case 270: - rot_enum = MM_UTIL_ROTATE_270; - break; - default: - debug_error("wrong rotate value"); - break; - } - - debug_log ("source buffer for rotation = %p and rotation = %d", src_buffer, rot_enum); - - ret = mm_util_rotate_image (src_buffer, - player->captured.width[0], player->captured.height[0], format, - dst_frame, &dst_width, &dst_height, rot_enum); - if (ret != MM_ERROR_NONE) - { - debug_error("failed to do rotate image"); - return ret; - } - - debug_log ("after rotation same stride: dst_width = %d and dst_height = %d", dst_width, dst_height); - - g_free (src_buffer); - - player->capture.data = dst_frame; - player->capture.size = dst_size; - player->capture.orientation = orientation; - player->capture.width = dst_width; - player->capture.height= dst_height; - - player->captured.width[0] = player->captured.stride_width[0] = dst_width; - player->captured.height[0] = player->captured.stride_height[0] = dst_height; - - return ret; -} - - -static gpointer -__mmplayer_capture_thread(gpointer data) -{ - mm_player_t* player = (mm_player_t*) data; - MMMessageParamType msg = {0, }; - unsigned char * linear_y_plane = NULL; - unsigned char * linear_uv_plane = NULL; - int orientation = 0; - int ret = 0; - - return_val_if_fail(player, NULL); - - while (!player->capture_thread_exit) - { - debug_log("capture thread started. waiting for signal"); - - g_mutex_lock(&player->capture_thread_mutex); - g_cond_wait(&player->capture_thread_cond, &player->capture_thread_mutex ); - - if ( player->capture_thread_exit ) - { - debug_log("exiting capture thread"); - goto EXIT; - } - debug_log("capture thread is recieved signal"); - - /* NOTE: Don't use MMPLAYER_CMD_LOCK() here. - * Because deadlock can be happened if other player api is used in message callback. - */ - if (player->video_cs == MM_PLAYER_COLORSPACE_NV12_TILED) - { - /* Colorspace conversion : NV12T-> NV12-> RGB888 */ - int ret = 0; - int linear_y_plane_size; - int linear_uv_plane_size; - int width = player->captured.width[0]; - int height = player->captured.height[0]; - unsigned char * src_buffer = NULL; - - linear_y_plane_size = (width * height); - linear_uv_plane_size = (width * height / 2); - - linear_y_plane = (unsigned char*) g_try_malloc(linear_y_plane_size); - if (linear_y_plane == NULL) - { - msg.code = MM_ERROR_PLAYER_NO_FREE_SPACE; - goto ERROR; - } - - linear_uv_plane = (unsigned char*) g_try_malloc(linear_uv_plane_size); - if (linear_uv_plane == NULL) - { - msg.code = MM_ERROR_PLAYER_NO_FREE_SPACE; - goto ERROR; - } - /* NV12 tiled to linear */ - __csc_tiled_to_linear_crop(linear_y_plane, - player->captured.data[0], width, height, 0,0,0,0); - __csc_tiled_to_linear_crop(linear_uv_plane, - player->captured.data[1], width, height / 2, 0,0,0,0); - - MMPLAYER_FREEIF(player->captured.data[0]); - MMPLAYER_FREEIF(player->captured.data[1]); - - src_buffer = (unsigned char*) g_try_malloc(linear_y_plane_size+linear_uv_plane_size); - - if (src_buffer == NULL) - { - msg.code = MM_ERROR_PLAYER_NO_FREE_SPACE; - goto ERROR; - } - memset(src_buffer, 0x00, linear_y_plane_size+linear_uv_plane_size); - memcpy(src_buffer, linear_y_plane, linear_y_plane_size); - memcpy(src_buffer+linear_y_plane_size, linear_uv_plane, linear_uv_plane_size); - - /* NV12 linear to RGB888 */ - ret = __mm_player_convert_colorspace(player, src_buffer, MM_UTIL_IMG_FMT_NV12, - width, height, MM_UTIL_IMG_FMT_RGB888); - - if (ret != MM_ERROR_NONE) - { - debug_error("failed to convert nv12 linear"); - goto ERROR; - } - /* clean */ - MMPLAYER_FREEIF(src_buffer); - MMPLAYER_FREEIF(linear_y_plane); - MMPLAYER_FREEIF(linear_uv_plane); - } else if (MM_PLAYER_COLORSPACE_NV12 == player->video_cs) { - #define MM_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) - int ret = 0; - char *src_buffer = NULL; - /* using original width otherwises, app can't know aligned to resize */ - int width_align = player->captured.width[0]; - int src_buffer_size = width_align * player->captured.height[0] * 3/2; - int i, j; - char*temp = NULL; - char*dst_buf = NULL; - - if (!src_buffer_size) { - debug_error("invalid data size"); - goto ERROR; - } - - src_buffer = (char*) g_try_malloc(src_buffer_size); - - if (!src_buffer) { - msg.code = MM_ERROR_PLAYER_NO_FREE_SPACE; - goto ERROR; - } - - memset(src_buffer, 0x00, src_buffer_size); - - temp = player->captured.data[0]; - dst_buf = src_buffer; - - /* set Y plane */ - for (i = 0; i < player->captured.height[0]; i++) { - memcpy(dst_buf, temp, width_align); - dst_buf += width_align; - temp += player->captured.stride_width[0]; - } - - temp = player->captured.data[1]; - - /* set UV plane*/ - for (j = 0; j < player->captured.height[1]; j++) { - memcpy(dst_buf, temp, width_align); - dst_buf += width_align; - temp += player->captured.stride_width[0]; - } - - /* free captured buf */ - MMPLAYER_FREEIF(player->captured.data[0]); - MMPLAYER_FREEIF(player->captured.data[1]); - - /* NV12 -> RGB888 */ - ret = __mm_player_convert_colorspace(player, (unsigned char*)src_buffer, MM_UTIL_IMG_FMT_NV12, - width_align, player->captured.height[0], MM_UTIL_IMG_FMT_RGB888); - if (ret != MM_ERROR_NONE) - { - debug_error("failed to convert nv12 linear"); - goto ERROR; - } - - } - - ret = _mmplayer_get_video_rotate_angle ((MMHandleType)player, &orientation); - if (ret != MM_ERROR_NONE) - { - debug_error("failed to get rotation angle"); - goto ERROR; - } - - debug_log ("orientation value = %d", orientation); - - ret = __mmplayer_handle_orientation (player, orientation, MM_UTIL_IMG_FMT_RGB888); - if (ret != MM_ERROR_NONE) - { - debug_error("failed to convert nv12 linear"); - goto ERROR; - } - - player->capture.fmt = MM_PLAYER_COLORSPACE_RGB888; - msg.data = &player->capture; - msg.size = player->capture.size; -// msg.captured_frame.width = player->capture.width; -// msg.captured_frame.height = player->capture.height; -// msg.captured_frame.orientation = player->capture.orientation; - - if (player->cmd >= MMPLAYER_COMMAND_START) - { - MMPLAYER_POST_MSG( player, MM_MESSAGE_VIDEO_CAPTURED, &msg ); - debug_log("returned from capture message callback"); - } - - g_mutex_unlock(&player->capture_thread_mutex); - - //MMPLAYER_FREEIF(player->capture.data); - continue; -ERROR: - if (player->video_cs == MM_PLAYER_COLORSPACE_NV12_TILED) - { - /* clean */ - MMPLAYER_FREEIF(linear_y_plane); - MMPLAYER_FREEIF(linear_uv_plane); - MMPLAYER_FREEIF(player->captured.data[0]); - MMPLAYER_FREEIF(player->captured.data[1]); - } - - msg.union_type = MM_MSG_UNION_CODE; - - g_mutex_unlock(&player->capture_thread_mutex); - MMPLAYER_POST_MSG( player, MM_MESSAGE_VIDEO_NOT_CAPTURED, &msg ); - } - return NULL; -EXIT: - g_mutex_unlock(&player->capture_thread_mutex); - return NULL; -} - -/** - * The output is fixed as RGB888 - */ -static int -__mmplayer_get_video_frame_from_buffer(mm_player_t* player, GstPad *pad, GstBuffer *buffer) -{ - gint yplane_size = 0; - gint uvplane_size = 0; - gint src_width = 0; - gint src_height = 0; - GstCaps *caps = NULL; - GstStructure *structure = NULL; - GstMapInfo mapinfo = GST_MAP_INFO_INIT; - GstMemory *memory = NULL; - mm_util_img_format src_fmt = MM_UTIL_IMG_FMT_YUV420; - mm_util_img_format dst_fmt = MM_UTIL_IMG_FMT_RGB888; // fixed - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - return_val_if_fail ( buffer, MM_ERROR_INVALID_ARGUMENT ); - - /* get fourcc */ - caps = gst_pad_get_current_caps(pad); - - return_val_if_fail ( caps, MM_ERROR_INVALID_ARGUMENT ); - MMPLAYER_LOG_GST_CAPS_TYPE(caps); - - structure = gst_caps_get_structure (caps, 0); - - return_val_if_fail (structure != NULL, MM_ERROR_PLAYER_INTERNAL); - - /* init capture image buffer */ - memset(&player->capture, 0x00, sizeof(MMPlayerVideoCapture)); - - gst_structure_get_int (structure, "width", &src_width); - gst_structure_get_int (structure, "height", &src_height); - - /* check rgb or yuv */ - if (gst_structure_has_name(structure, "video/x-raw")) - { - /* NV12T */ - const gchar *gst_format = gst_structure_get_string(structure, "format"); - if(!g_strcmp0(gst_format, "ST12") || !g_strcmp0(gst_format, "SN12")) - { - guint n; - debug_msg ("captured format is %s\n", gst_format); - - MMVideoBuffer *proved = NULL; - if(!g_strcmp0(gst_format, "ST12")) - player->video_cs = MM_PLAYER_COLORSPACE_NV12_TILED; - else - player->video_cs = MM_PLAYER_COLORSPACE_NV12; - - /* get video frame info from proved buffer */ - n = gst_buffer_n_memory(buffer); - memory = gst_buffer_peek_memory(buffer, n-1); - gst_memory_map(memory, &mapinfo, GST_MAP_READ); - proved = (MMVideoBuffer *)mapinfo.data; - - if ( !proved || !proved->data[0] || !proved->data[1] ) { - debug_error("fail to gst_memory_map"); - return MM_ERROR_PLAYER_INTERNAL; - } - -#if 0 - yplane_size = proved->size[0]; - uvplane_size = proved->size[1]; -#else - yplane_size = proved->stride_width[0] * proved->stride_height[0]; - uvplane_size = proved->stride_width[1] * proved->stride_height[1]; -#endif - - debug_msg ("yplane_size=%d, uvplane_size=%d\n", yplane_size, uvplane_size); - memset(&player->captured, 0x00, sizeof(MMVideoBuffer)); - memcpy(&player->captured, proved, sizeof(MMVideoBuffer)); - - player->captured.data[0] = g_try_malloc(yplane_size); - if ( !player->captured.data[0] ) { - gst_memory_unmap(memory, &mapinfo); - return MM_ERROR_SOUND_NO_FREE_SPACE; - } - - player->captured.data[1] = g_try_malloc(uvplane_size); - if ( !player->captured.data[1] ) { - gst_memory_unmap(memory, &mapinfo); - return MM_ERROR_SOUND_NO_FREE_SPACE; - } - - memcpy(player->captured.data[0], proved->data[0], yplane_size); - memcpy(player->captured.data[1], proved->data[1], uvplane_size); - - gst_memory_unmap(memory, &mapinfo); - - goto DONE; - } - else - { - GstVideoInfo format_info; - gst_video_info_from_caps(&format_info, caps); - - switch(GST_VIDEO_INFO_FORMAT(&format_info)) - { - case GST_VIDEO_FORMAT_I420: - src_fmt = MM_UTIL_IMG_FMT_I420; - break; - case GST_VIDEO_FORMAT_BGRA: - src_fmt = MM_UTIL_IMG_FMT_BGRA8888; - break; - case GST_VIDEO_FORMAT_BGRx: - src_fmt = MM_UTIL_IMG_FMT_BGRX8888; - break; - default: - goto UNKNOWN; - break; - } - } - } - else - { - goto UNKNOWN; - } - - gst_buffer_map(buffer, &mapinfo, GST_MAP_READ); - __mm_player_convert_colorspace(player, mapinfo.data, src_fmt, src_width, src_height, dst_fmt); - gst_buffer_unmap(buffer, &mapinfo); - -DONE: - /* do convert colorspace */ - g_cond_signal( &player->capture_thread_cond ); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; - -UNKNOWN: - debug_error("unknown format to capture\n"); - return MM_ERROR_PLAYER_INTERNAL; -} - -static GstPadProbeReturn -__mmplayer_video_capture_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data) -{ - mm_player_t* player = (mm_player_t*) u_data; - GstBuffer *buffer = NULL; - int ret = MM_ERROR_NONE; - - return_val_if_fail (info->data, GST_PAD_PROBE_REMOVE); - MMPLAYER_FENTER(); - - buffer = gst_pad_probe_info_get_buffer(info); - ret = __mmplayer_get_video_frame_from_buffer(player, pad, buffer); - - if ( ret != MM_ERROR_NONE) - { - debug_error("failed to get video frame"); - return GST_PAD_PROBE_REMOVE; - } - - /* remove probe to be called at one time */ - if (player->video_capture_cb_probe_id) - { - gst_pad_remove_probe(pad, player->video_capture_cb_probe_id); - player->video_capture_cb_probe_id = 0; - } - - MMPLAYER_FLEAVE(); - - return GST_PAD_PROBE_OK; -} - -static int -__mm_player_convert_colorspace(mm_player_t* player, unsigned char* src_data, mm_util_img_format src_fmt, unsigned int src_w, unsigned int src_h, mm_util_img_format dst_fmt) -{ - unsigned char *dst_data = NULL; - unsigned int dst_size; - int ret = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_INTERNAL); - ret = mm_util_get_image_size(dst_fmt, src_w, src_h, &dst_size); - - if (ret != MM_ERROR_NONE) - { - debug_error("failed to get image size for capture, %d\n", ret); - return MM_ERROR_PLAYER_INTERNAL; - } - - secure_debug_log("width: %d, height: %d to capture, dest size: %d\n", src_w, src_h, dst_size); - - dst_data = (unsigned char*)g_malloc0(dst_size); - - if (!dst_data) - { - debug_error("no free space to capture\n"); - return MM_ERROR_PLAYER_NO_FREE_SPACE; - } - - ret = mm_util_convert_colorspace(src_data, src_w, src_h, src_fmt, dst_data, dst_fmt); - - if (ret != MM_ERROR_NONE) - { - debug_error("failed to convert for capture, %d\n", ret); - return MM_ERROR_PLAYER_INTERNAL; - } - - player->capture.size = dst_size; - player->capture.data = dst_data; - - return MM_ERROR_NONE; -} - -/* - * Get tiled address of position(x,y) - * - * @param x_size - * width of tiled[in] - * - * @param y_size - * height of tiled[in] - * - * @param x_pos - * x position of tield[in] - * - * @param src_size - * y position of tield[in] - * - * @return - * address of tiled data - */ -static int -__tile_4x2_read(int x_size, int y_size, int x_pos, int y_pos) -{ - int pixel_x_m1, pixel_y_m1; - int roundup_x; - int linear_addr0, linear_addr1, bank_addr ; - int x_addr; - int trans_addr; - - pixel_x_m1 = x_size -1; - pixel_y_m1 = y_size -1; - - roundup_x = ((pixel_x_m1 >> 7) + 1); - - x_addr = x_pos >> 2; - - if ((y_size <= y_pos+32) && ( y_pos < y_size) && - (((pixel_y_m1 >> 5) & 0x1) == 0) && (((y_pos >> 5) & 0x1) == 0)) { - linear_addr0 = (((y_pos & 0x1f) <<4) | (x_addr & 0xf)); - linear_addr1 = (((y_pos >> 6) & 0xff) * roundup_x + ((x_addr >> 6) & 0x3f)); - - if (((x_addr >> 5) & 0x1) == ((y_pos >> 5) & 0x1)) - bank_addr = ((x_addr >> 4) & 0x1); - else - bank_addr = 0x2 | ((x_addr >> 4) & 0x1); - } else { - linear_addr0 = (((y_pos & 0x1f) << 4) | (x_addr & 0xf)); - linear_addr1 = (((y_pos >> 6) & 0xff) * roundup_x + ((x_addr >> 5) & 0x7f)); - - if (((x_addr >> 5) & 0x1) == ((y_pos >> 5) & 0x1)) - bank_addr = ((x_addr >> 4) & 0x1); - else - bank_addr = 0x2 | ((x_addr >> 4) & 0x1); - } - - linear_addr0 = linear_addr0 << 2; - trans_addr = (linear_addr1 <<13) | (bank_addr << 11) | linear_addr0; - - return trans_addr; -} - -/* - * Converts tiled data to linear - * Crops left, top, right, buttom - * 1. Y of NV12T to Y of YUV420P - * 2. Y of NV12T to Y of YUV420S - * 3. UV of NV12T to UV of YUV420S - * - * @param yuv420_dest - * Y or UV plane address of YUV420[out] - * - * @param nv12t_src - * Y or UV plane address of NV12T[in] - * - * @param yuv420_width - * Width of YUV420[in] - * - * @param yuv420_height - * Y: Height of YUV420, UV: Height/2 of YUV420[in] - * - * @param left - * Crop size of left - * - * @param top - * Crop size of top - * - * @param right - * Crop size of right - * - * @param buttom - * Crop size of buttom - */ -static void -__csc_tiled_to_linear_crop(unsigned char *yuv420_dest, unsigned char *nv12t_src, int yuv420_width, int yuv420_height, - int left, int top, int right, int buttom) -{ - int i, j; - int tiled_offset = 0, tiled_offset1 = 0; - int linear_offset = 0; - int temp1 = 0, temp2 = 0, temp3 = 0, temp4 = 0; - - temp3 = yuv420_width-right; - temp1 = temp3-left; - /* real width is greater than or equal 256 */ - if (temp1 >= 256) { - for (i=top; i>8)<<8; - temp3 = temp3>>6; - temp4 = i>>5; - if (temp4 & 0x1) { - /* odd fomula: 2+x+(x>>2)<<2+x_block_num*(y-1) */ - tiled_offset = temp4-1; - temp1 = ((yuv420_width+127)>>7)<<7; - tiled_offset = tiled_offset*(temp1>>6); - tiled_offset = tiled_offset+temp3; - tiled_offset = tiled_offset+2; - temp1 = (temp3>>2)<<2; - tiled_offset = tiled_offset+temp1; - tiled_offset = tiled_offset<<11; - tiled_offset1 = tiled_offset+2048*2; - temp4 = 8; - } else { - temp2 = ((yuv420_height+31)>>5)<<5; - if ((i+32)>2)<<2+x_block_num*y */ - temp1 = temp3+2; - temp1 = (temp1>>2)<<2; - tiled_offset = temp3+temp1; - temp1 = ((yuv420_width+127)>>7)<<7; - tiled_offset = tiled_offset+temp4*(temp1>>6); - tiled_offset = tiled_offset<<11; - tiled_offset1 = tiled_offset+2048*6; - temp4 = 8; - } else { - /* even2 fomula: x+x_block_num*y */ - temp1 = ((yuv420_width+127)>>7)<<7; - tiled_offset = temp4*(temp1>>6); - tiled_offset = tiled_offset+temp3; - tiled_offset = tiled_offset<<11; - tiled_offset1 = tiled_offset+2048*2; - temp4 = 4; - } - } - - temp1 = i&0x1F; - tiled_offset = tiled_offset+64*(temp1); - tiled_offset1 = tiled_offset1+64*(temp1); - temp2 = yuv420_width-left-right; - linear_offset = temp2*(i-top); - temp3 = ((j+256)>>8)<<8; - temp3 = temp3-j; - temp1 = left&0x3F; - if (temp3 > 192) { - memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset+temp1, 64-temp1); - temp2 = ((left+63)>>6)<<6; - temp3 = ((yuv420_width-right)>>6)<<6; - if (temp2 == temp3) { - temp2 = yuv420_width-right-(64-temp1); - } - memcpy(yuv420_dest+linear_offset+64-temp1, nv12t_src+tiled_offset+2048, 64); - memcpy(yuv420_dest+linear_offset+128-temp1, nv12t_src+tiled_offset1, 64); - memcpy(yuv420_dest+linear_offset+192-temp1, nv12t_src+tiled_offset1+2048, 64); - linear_offset = linear_offset+256-temp1; - } else if (temp3 > 128) { - memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset+2048+temp1, 64-temp1); - memcpy(yuv420_dest+linear_offset+64-temp1, nv12t_src+tiled_offset1, 64); - memcpy(yuv420_dest+linear_offset+128-temp1, nv12t_src+tiled_offset1+2048, 64); - linear_offset = linear_offset+192-temp1; - } else if (temp3 > 64) { - memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset1+temp1, 64-temp1); - memcpy(yuv420_dest+linear_offset+64-temp1, nv12t_src+tiled_offset1+2048, 64); - linear_offset = linear_offset+128-temp1; - } else if (temp3 > 0) { - memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset1+2048+temp1, 64-temp1); - linear_offset = linear_offset+64-temp1; - } - - tiled_offset = tiled_offset+temp4*2048; - j = (left>>8)<<8; - j = j + 256; - temp2 = yuv420_width-right-256; - for (; j<=temp2; j=j+256) { - memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); - tiled_offset1 = tiled_offset1+temp4*2048; - memcpy(yuv420_dest+linear_offset+64, nv12t_src+tiled_offset+2048, 64); - memcpy(yuv420_dest+linear_offset+128, nv12t_src+tiled_offset1, 64); - tiled_offset = tiled_offset+temp4*2048; - memcpy(yuv420_dest+linear_offset+192, nv12t_src+tiled_offset1+2048, 64); - linear_offset = linear_offset+256; - } - - tiled_offset1 = tiled_offset1+temp4*2048; - temp2 = yuv420_width-right-j; - if (temp2 > 192) { - memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); - memcpy(yuv420_dest+linear_offset+64, nv12t_src+tiled_offset+2048, 64); - memcpy(yuv420_dest+linear_offset+128, nv12t_src+tiled_offset1, 64); - memcpy(yuv420_dest+linear_offset+192, nv12t_src+tiled_offset1+2048, temp2-192); - } else if (temp2 > 128) { - memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); - memcpy(yuv420_dest+linear_offset+64, nv12t_src+tiled_offset+2048, 64); - memcpy(yuv420_dest+linear_offset+128, nv12t_src+tiled_offset1, temp2-128); - } else if (temp2 > 64) { - memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); - memcpy(yuv420_dest+linear_offset+64, nv12t_src+tiled_offset+2048, temp2-64); - } else { - memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, temp2); - } - } - } else if (temp1 >= 64) { - for (i=top; i<(yuv420_height-buttom); i=i+1) { - j = left; - tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i); - temp2 = ((j+64)>>6)<<6; - temp2 = temp2-j; - linear_offset = temp1*(i-top); - temp4 = j&0x3; - tiled_offset = tiled_offset+temp4; - memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, temp2); - linear_offset = linear_offset+temp2; - j = j+temp2; - if ((j+64) <= temp3) { - tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i); - memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); - linear_offset = linear_offset+64; - j = j+64; - } - if ((j+64) <= temp3) { - tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i); - memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); - linear_offset = linear_offset+64; - j = j+64; - } - if (j < temp3) { - tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i); - temp2 = temp3-j; - memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, temp2); - } - } - } else { - for (i=top; i<(yuv420_height-buttom); i=i+1) { - linear_offset = temp1*(i-top); - for (j=left; j<(yuv420_width-right); j=j+2) { - tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i); - temp4 = j&0x3; - tiled_offset = tiled_offset+temp4; - memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 2); - linear_offset = linear_offset+2; - } - } - } -} diff --git a/src/mm_player_common_priv.c b/src/mm_player_common_priv.c new file mode 100644 index 0000000..6d0f500 --- /dev/null +++ b/src/mm_player_common_priv.c @@ -0,0 +1,1029 @@ +/* + * libmm-player + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , YeJin Cho , + * Seungbae Shin , YoungHwan An + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*=========================================================================================== +| | +| INCLUDE FILES | +| | +========================================================================================== */ +#include +#include +#include +#include +#ifdef HAVE_WAYLAND +#include +#endif +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "mm_player_priv.h" +#include "mm_player_ini.h" +#include "mm_player_attrs.h" +#include "mm_player_utils.h" +#include + +/*=========================================================================================== +| | +| LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE | +| | +========================================================================================== */ + +/*--------------------------------------------------------------------------- +| GLOBAL CONSTANT DEFINITIONS: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| IMPORTED VARIABLE DECLARATIONS: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| IMPORTED FUNCTION DECLARATIONS: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| LOCAL #defines: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| LOCAL CONSTANT DEFINITIONS: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| LOCAL DATA TYPE DEFINITIONS: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| GLOBAL VARIABLE DEFINITIONS: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| LOCAL VARIABLE DEFINITIONS: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| LOCAL FUNCTION PROTOTYPES: | +---------------------------------------------------------------------------*/ +static gint __gst_transform_gsterror( mm_player_t* player, GstMessage * message, GError* error); + +/*=========================================================================================== +| | +| FUNCTION DEFINITIONS | +| | +========================================================================================== */ +int +__mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command) +{ + MMPlayerStateType current_state = MM_PLAYER_STATE_NUM; + MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM; +// MMPlayerStateType target_state = MM_PLAYER_STATE_NUM; +// MMPlayerStateType prev_state = MM_PLAYER_STATE_NUM; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + //debug_log("incomming command : %d \n", command ); + + current_state = MMPLAYER_CURRENT_STATE(player); + pending_state = MMPLAYER_PENDING_STATE(player); +// target_state = MMPLAYER_TARGET_STATE(player); +// prev_state = MMPLAYER_PREV_STATE(player); + + MMPLAYER_PRINT_STATE(player); + + switch( command ) + { + case MMPLAYER_COMMAND_CREATE: + { + MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL; + + if ( current_state == MM_PLAYER_STATE_NULL || + current_state == MM_PLAYER_STATE_READY || + current_state == MM_PLAYER_STATE_PAUSED || + current_state == MM_PLAYER_STATE_PLAYING ) + goto NO_OP; + } + break; + + case MMPLAYER_COMMAND_DESTROY: + { + /* destroy can called anytime */ + + MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE; + } + break; + + case MMPLAYER_COMMAND_REALIZE: + { + MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY; + + if ( pending_state != MM_PLAYER_STATE_NONE ) + { + goto INVALID_STATE; + } + else + { + /* need ready state to realize */ + if ( current_state == MM_PLAYER_STATE_READY ) + goto NO_OP; + + if ( current_state != MM_PLAYER_STATE_NULL ) + goto INVALID_STATE; + } + } + break; + + case MMPLAYER_COMMAND_UNREALIZE: + { + MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL; + + if ( current_state == MM_PLAYER_STATE_NULL ) + goto NO_OP; + } + break; + + case MMPLAYER_COMMAND_START: + { + MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING; + + if ( pending_state == MM_PLAYER_STATE_NONE ) + { + if ( current_state == MM_PLAYER_STATE_PLAYING ) + goto NO_OP; + else if ( current_state != MM_PLAYER_STATE_READY && + current_state != MM_PLAYER_STATE_PAUSED ) + goto INVALID_STATE; + } + else if ( pending_state == MM_PLAYER_STATE_PLAYING ) + { + goto ALREADY_GOING; + } + else if ( pending_state == MM_PLAYER_STATE_PAUSED ) + { + debug_log("player is going to paused state, just change the pending state as playing"); + } + else + { + goto INVALID_STATE; + } + } + break; + + case MMPLAYER_COMMAND_STOP: + { + MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY; + + if ( current_state == MM_PLAYER_STATE_READY ) + goto NO_OP; + + /* need playing/paused state to stop */ + if ( current_state != MM_PLAYER_STATE_PLAYING && + current_state != MM_PLAYER_STATE_PAUSED ) + goto INVALID_STATE; + } + break; + + case MMPLAYER_COMMAND_PAUSE: + { + if ( MMPLAYER_IS_LIVE_STREAMING( player ) ) + goto NO_OP; + + if (player->doing_seek) + goto NOT_COMPLETED_SEEK; + + MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED; + + if ( pending_state == MM_PLAYER_STATE_NONE ) + { + if ( current_state == MM_PLAYER_STATE_PAUSED ) + goto NO_OP; + else if ( current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY ) // support loading state of broswer + goto INVALID_STATE; + } + else if ( pending_state == MM_PLAYER_STATE_PAUSED ) + { + goto ALREADY_GOING; + } + else if ( pending_state == MM_PLAYER_STATE_PLAYING ) + { + if ( current_state == MM_PLAYER_STATE_PAUSED ) { + debug_log("player is PAUSED going to PLAYING, just change the pending state as PAUSED"); + } else { + goto INVALID_STATE; + } + } + } + break; + + case MMPLAYER_COMMAND_RESUME: + { + + if (player->doing_seek) + goto NOT_COMPLETED_SEEK; + + MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING; + + if ( pending_state == MM_PLAYER_STATE_NONE ) + { + if ( current_state == MM_PLAYER_STATE_PLAYING ) + goto NO_OP; + else if ( current_state != MM_PLAYER_STATE_PAUSED ) + goto INVALID_STATE; + } + else if ( pending_state == MM_PLAYER_STATE_PLAYING ) + { + goto ALREADY_GOING; + } + else if ( pending_state == MM_PLAYER_STATE_PAUSED ) + { + debug_log("player is going to paused state, just change the pending state as playing"); + } + else + { + goto INVALID_STATE; + } + } + break; + + default: + break; + } + player->cmd = command; + + return MM_ERROR_NONE; + +INVALID_STATE: + debug_warning("since player is in wrong state(%s). it's not able to apply the command(%d)", + MMPLAYER_STATE_GET_NAME(current_state), command); + return MM_ERROR_PLAYER_INVALID_STATE; + +NOT_COMPLETED_SEEK: + debug_warning("not completed seek"); + return MM_ERROR_PLAYER_DOING_SEEK; + +NO_OP: + debug_warning("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state)); + return MM_ERROR_PLAYER_NO_OP; + +ALREADY_GOING: + debug_warning("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state)); + return MM_ERROR_PLAYER_NO_OP; +} + +int +__mmplayer_gst_set_state (mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout) // @ +{ + GstState element_state = GST_STATE_VOID_PENDING; + GstState element_pending_state = GST_STATE_VOID_PENDING; + GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + return_val_if_fail ( element, MM_ERROR_INVALID_ARGUMENT ); + + debug_log("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state)); + + /* set state */ + ret = gst_element_set_state(element, state); + + if ( ret == GST_STATE_CHANGE_FAILURE ) + { + debug_error("failed to set [%s] state\n", GST_ELEMENT_NAME(element)); + + /* dump state of all element */ + __mmplayer_dump_pipeline_state( player ); + + return MM_ERROR_PLAYER_INTERNAL; + } + + /* return here so state transition to be done in async mode */ + if ( async ) + { + debug_log("async state transition. not waiting for state complete.\n"); + return MM_ERROR_NONE; + } + + /* wait for state transition */ + ret = gst_element_get_state( element, &element_state, &element_pending_state, timeout * GST_SECOND ); + + if ( ret == GST_STATE_CHANGE_FAILURE || ( state != element_state ) ) + { + debug_error("failed to change [%s] element state to [%s] within %d sec\n", + GST_ELEMENT_NAME(element), + gst_element_state_get_name(state), timeout ); + + debug_error(" [%s] state : %s pending : %s \n", + GST_ELEMENT_NAME(element), + gst_element_state_get_name(element_state), + gst_element_state_get_name(element_pending_state) ); + + /* dump state of all element */ + __mmplayer_dump_pipeline_state( player ); + + return MM_ERROR_PLAYER_INTERNAL; + } + + debug_log("[%s] element state has changed\n", GST_ELEMENT_NAME(element)); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +void __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id) +{ + GSource *source = NULL; + + MMPLAYER_FENTER(); + + source = g_main_context_find_source_by_id (context, source_id); + + if (source != NULL) + { + debug_warning("context: %p, source id: %d, source: %p", context, source_id, source); + g_source_destroy(source); + } + + MMPLAYER_FLEAVE(); +} + +gboolean +__mmplayer_dump_pipeline_state( mm_player_t* player ) +{ + GstIterator*iter = NULL; + gboolean done = FALSE; + + GValue item = {0, }; + GstElement *element = NULL; + GstElementFactory *factory = NULL; + + GstState state = GST_STATE_VOID_PENDING; + GstState pending = GST_STATE_VOID_PENDING; + GstClockTime time = 200*GST_MSECOND; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player && + player->pipeline && + player->pipeline->mainbin, + FALSE ); + + iter = gst_bin_iterate_recurse(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) ); + + if ( iter != NULL ) + { + while (!done) { + switch ( gst_iterator_next (iter, &item) ) + { + case GST_ITERATOR_OK: + element = g_value_get_object(&item); + gst_element_get_state(element,&state, &pending,time); + + factory = gst_element_get_factory (element) ; + if (factory) + { + debug_error("%s:%s : From:%s To:%s refcount : %d\n", GST_OBJECT_NAME(factory) , GST_ELEMENT_NAME(element) , + gst_element_state_get_name(state), gst_element_state_get_name(pending) , GST_OBJECT_REFCOUNT_VALUE(element)); + } + g_value_reset (&item); + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iter); + break; + case GST_ITERATOR_ERROR: + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + } + + element = GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst); + + gst_element_get_state(element,&state, &pending,time); + + factory = gst_element_get_factory (element) ; + + if (factory) + { + debug_error("%s:%s : From:%s To:%s refcount : %d\n", + GST_OBJECT_NAME(factory), + GST_ELEMENT_NAME(element), + gst_element_state_get_name(state), + gst_element_state_get_name(pending), + GST_OBJECT_REFCOUNT_VALUE(element) ); + } + + g_value_unset(&item); + + if ( iter ) + gst_iterator_free (iter); + + MMPLAYER_FLEAVE(); + + return FALSE; +} + +const gchar * +__get_state_name ( int state ) +{ + switch ( state ) + { + case MM_PLAYER_STATE_NULL: + return "NULL"; + case MM_PLAYER_STATE_READY: + return "READY"; + case MM_PLAYER_STATE_PAUSED: + return "PAUSED"; + case MM_PLAYER_STATE_PLAYING: + return "PLAYING"; + case MM_PLAYER_STATE_NONE: + return "NONE"; + default: + return "INVAID"; + } +} + +gboolean +__is_rtsp_streaming ( mm_player_t* player ) +{ + return_val_if_fail ( player, FALSE ); + + return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_RTSP ) ? TRUE : FALSE; +} + +gboolean +__is_wfd_streaming ( mm_player_t* player ) +{ + return_val_if_fail ( player, FALSE ); + + return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_WFD ) ? TRUE : FALSE; +} + +gboolean +__is_http_streaming ( mm_player_t* player ) +{ + return_val_if_fail ( player, FALSE ); + + return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_HTTP ) ? TRUE : FALSE; +} + +gboolean +__is_streaming ( mm_player_t* player ) +{ + return_val_if_fail ( player, FALSE ); + + return ( __is_http_progressive_down( player ) || __is_rtsp_streaming ( player ) || __is_wfd_streaming ( player ) || __is_http_streaming ( player ) + || __is_http_live_streaming ( player ) || __is_dash_streaming ( player ) || __is_smooth_streaming(player) ) ? TRUE : FALSE; +} + +gboolean +__is_live_streaming ( mm_player_t* player ) +{ + return_val_if_fail ( player, FALSE ); + + return ( __is_rtsp_streaming ( player ) && player->streaming_type == STREAMING_SERVICE_LIVE ) ? TRUE : FALSE; +} + +gboolean +__is_http_live_streaming( mm_player_t* player ) +{ + return_val_if_fail( player, FALSE ); + + return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS ) ? TRUE : FALSE; +} + +gboolean +__is_dash_streaming ( mm_player_t* player ) +{ + return_val_if_fail ( player, FALSE ); + + return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_DASH ) ? TRUE : FALSE; +} + +gboolean +__is_smooth_streaming ( mm_player_t* player ) +{ + return_val_if_fail ( player, FALSE ); + + return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_SS ) ? TRUE : FALSE; +} + + +gboolean +__is_http_progressive_down(mm_player_t* player) +{ + return_val_if_fail( player, FALSE ); + + return ((player->pd_mode) ? TRUE:FALSE); +} +/* if retval is FALSE, it will be dropped for perfomance. */ +gboolean +__mmplayer_check_useful_message(mm_player_t *player, GstMessage * message) +{ + gboolean retval = FALSE; + + if ( !(player->pipeline && player->pipeline->mainbin) ) + { + debug_error("player pipeline handle is null"); + return TRUE; + } + + switch (GST_MESSAGE_TYPE (message)) + { + case GST_MESSAGE_TAG: + case GST_MESSAGE_EOS: + case GST_MESSAGE_ERROR: + case GST_MESSAGE_WARNING: + case GST_MESSAGE_CLOCK_LOST: + case GST_MESSAGE_NEW_CLOCK: + case GST_MESSAGE_ELEMENT: + case GST_MESSAGE_DURATION_CHANGED: + case GST_MESSAGE_ASYNC_START: + retval = TRUE; + break; + case GST_MESSAGE_ASYNC_DONE: + case GST_MESSAGE_STATE_CHANGED: + /* we only handle messages from pipeline */ + if(( message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst ) && (!player->gapless.reconfigure)) + retval = TRUE; + else + retval = FALSE; + break; + case GST_MESSAGE_BUFFERING: + { + gint buffer_percent = 0; + + gst_message_parse_buffering (message, &buffer_percent); + + if ((MMPLAYER_IS_STREAMING(player)) && + (player->streamer) && + (player->streamer->is_buffering == TRUE) && + (buffer_percent == MAX_BUFFER_PERCENT)) + { + debug_log (">>> [%s] Buffering DONE is detected !!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message))); + player->streamer->is_buffering_done = TRUE; + } + + retval = TRUE; + break; + } + default: + retval = FALSE; + break; + } + + return retval; +} + +gboolean +__mmplayer_handle_gst_error ( mm_player_t* player, GstMessage * message, GError* error ) +{ + MMMessageParamType msg_param; + gchar *msg_src_element; + + MMPLAYER_FENTER(); + + return_val_if_fail( player, FALSE ); + return_val_if_fail( error, FALSE ); + + /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */ + + memset (&msg_param, 0, sizeof(MMMessageParamType)); + + if ( error->domain == GST_CORE_ERROR ) + { + msg_param.code = __gst_handle_core_error( player, error->code ); + } + else if ( error->domain == GST_LIBRARY_ERROR ) + { + msg_param.code = __gst_handle_library_error( player, error->code ); + } + else if ( error->domain == GST_RESOURCE_ERROR ) + { + msg_param.code = __gst_handle_resource_error( player, error->code ); + } + else if ( error->domain == GST_STREAM_ERROR ) + { + msg_param.code = __gst_handle_stream_error( player, error, message ); + } + else + { + debug_warning("This error domain is not defined.\n"); + + /* we treat system error as an internal error */ + msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM; + } + + if ( message->src ) + { + msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( message->src ) ); + + msg_param.data = (void *) error->message; + + debug_error("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]\n", + msg_src_element, g_quark_to_string (error->domain), error->message, error->code, msg_param.code); + } + + /* no error */ + if (msg_param.code == MM_ERROR_NONE) + return TRUE; + + /* post error to application */ + if ( ! player->msg_posted ) + { + MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param ); + /* don't post more if one was sent already */ + player->msg_posted = TRUE; + } + else + { + debug_log("skip error post because it's sent already.\n"); + } + + MMPLAYER_FLEAVE(); + + return TRUE; +} + + +gint +__gst_handle_core_error( mm_player_t* player, int code ) +{ + gint trans_err = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + switch ( code ) + { + case GST_CORE_ERROR_MISSING_PLUGIN: + return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT; + case GST_CORE_ERROR_STATE_CHANGE: + case GST_CORE_ERROR_SEEK: + case GST_CORE_ERROR_NOT_IMPLEMENTED: + case GST_CORE_ERROR_FAILED: + case GST_CORE_ERROR_TOO_LAZY: + case GST_CORE_ERROR_PAD: + case GST_CORE_ERROR_THREAD: + case GST_CORE_ERROR_NEGOTIATION: + case GST_CORE_ERROR_EVENT: + case GST_CORE_ERROR_CAPS: + case GST_CORE_ERROR_TAG: + case GST_CORE_ERROR_CLOCK: + case GST_CORE_ERROR_DISABLED: + default: + trans_err = MM_ERROR_PLAYER_INVALID_STREAM; + break; + } + + MMPLAYER_FLEAVE(); + + return trans_err; +} + +gint +__gst_handle_library_error( mm_player_t* player, int code ) +{ + gint trans_err = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + switch ( code ) + { + case GST_LIBRARY_ERROR_FAILED: + case GST_LIBRARY_ERROR_TOO_LAZY: + case GST_LIBRARY_ERROR_INIT: + case GST_LIBRARY_ERROR_SHUTDOWN: + case GST_LIBRARY_ERROR_SETTINGS: + case GST_LIBRARY_ERROR_ENCODE: + default: + trans_err = MM_ERROR_PLAYER_INVALID_STREAM; + break; + } + + MMPLAYER_FLEAVE(); + + return trans_err; +} + + +gint +__gst_handle_resource_error( mm_player_t* player, int code ) +{ + gint trans_err = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + switch ( code ) + { + case GST_RESOURCE_ERROR_NO_SPACE_LEFT: + trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE; + break; + case GST_RESOURCE_ERROR_NOT_FOUND: + case GST_RESOURCE_ERROR_OPEN_READ: + if ( MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING ( player ) + || MMPLAYER_IS_RTSP_STREAMING(player)) + { + trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL; + break; + } + case GST_RESOURCE_ERROR_READ: + if ( MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING ( player ) + || MMPLAYER_IS_RTSP_STREAMING(player)) + { + trans_err = MM_ERROR_PLAYER_STREAMING_FAIL; + break; + } + case GST_RESOURCE_ERROR_WRITE: + case GST_RESOURCE_ERROR_FAILED: + case GST_RESOURCE_ERROR_SEEK: + case GST_RESOURCE_ERROR_TOO_LAZY: + case GST_RESOURCE_ERROR_BUSY: + case GST_RESOURCE_ERROR_OPEN_WRITE: + case GST_RESOURCE_ERROR_OPEN_READ_WRITE: + case GST_RESOURCE_ERROR_CLOSE: + case GST_RESOURCE_ERROR_SYNC: + case GST_RESOURCE_ERROR_SETTINGS: + default: + trans_err = MM_ERROR_PLAYER_INTERNAL; + break; + } + + MMPLAYER_FLEAVE(); + + return trans_err; +} + + +gint +__gst_handle_stream_error( mm_player_t* player, GError* error, GstMessage * message ) +{ + gint trans_err = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + return_val_if_fail( error, MM_ERROR_INVALID_ARGUMENT ); + return_val_if_fail ( message, MM_ERROR_INVALID_ARGUMENT ); + + switch ( error->code ) + { + case GST_STREAM_ERROR_FAILED: + case GST_STREAM_ERROR_TYPE_NOT_FOUND: + case GST_STREAM_ERROR_DECODE: + case GST_STREAM_ERROR_WRONG_TYPE: + case GST_STREAM_ERROR_DECRYPT: + case GST_STREAM_ERROR_DECRYPT_NOKEY: + case GST_STREAM_ERROR_CODEC_NOT_FOUND: + trans_err = __gst_transform_gsterror( player, message, error ); + break; + + case GST_STREAM_ERROR_NOT_IMPLEMENTED: + case GST_STREAM_ERROR_TOO_LAZY: + case GST_STREAM_ERROR_ENCODE: + case GST_STREAM_ERROR_DEMUX: + case GST_STREAM_ERROR_MUX: + case GST_STREAM_ERROR_FORMAT: + default: + trans_err = MM_ERROR_PLAYER_INVALID_STREAM; + break; + } + + MMPLAYER_FLEAVE(); + + return trans_err; +} + +/* NOTE : decide gstreamer state whether there is some playable track or not. */ +static gint +__gst_transform_gsterror( mm_player_t* player, GstMessage * message, GError* error ) +{ + gchar *src_element_name = NULL; + GstElement *src_element = NULL; + GstElementFactory *factory = NULL; + const gchar* klass = NULL; + + MMPLAYER_FENTER(); + + /* FIXIT */ + return_val_if_fail ( message, MM_ERROR_INVALID_ARGUMENT ); + return_val_if_fail ( message->src, MM_ERROR_INVALID_ARGUMENT ); + return_val_if_fail ( error, MM_ERROR_INVALID_ARGUMENT ); + + src_element = GST_ELEMENT_CAST(message->src); + if ( !src_element ) + goto INTERNAL_ERROR; + + src_element_name = GST_ELEMENT_NAME(src_element); + if ( !src_element_name ) + goto INTERNAL_ERROR; + + factory = gst_element_get_factory(src_element); + if ( !factory ) + goto INTERNAL_ERROR; + + klass = gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS); + if ( !klass ) + goto INTERNAL_ERROR; + + debug_log("error code=%d, msg=%s, src element=%s, class=%s\n", + error->code, error->message, src_element_name, klass); + + //<- + { + if (player->selector) { + int msg_src_pos = 0; + gint active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index; + debug_log ("current active pad index -%d", active_pad_index); + + if (src_element_name) { + int idx = 0; + + if (player->audio_decoders) { + GList *adec = player->audio_decoders; + for ( ;adec ; adec = g_list_next(adec)) { + gchar *name = adec->data; + + debug_log("found audio decoder name = %s", name); + if (g_strrstr(name, src_element_name)) { + msg_src_pos = idx; + break; + } + idx++; + } + } + debug_log("active pad = %d, error src index = %d", active_pad_index, msg_src_pos); + } + + if (active_pad_index != msg_src_pos) { + debug_log("skip error because error is posted from no activated track"); + return MM_ERROR_NONE; + } + } + } + //-> temp code + + switch ( error->code ) + { + case GST_STREAM_ERROR_DECODE: + { + /* Demuxer can't parse one track because it's corrupted. + * So, the decoder for it is not linked. + * But, it has one playable track. + */ + if ( g_strrstr(klass, "Demux") ) + { + if ( player->can_support_codec == FOUND_PLUGIN_VIDEO ) + { + return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND; + } + else if ( player->can_support_codec == FOUND_PLUGIN_AUDIO ) + { + return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND; + } + else + { + if ( player->pipeline->audiobin ) // PCM + { + return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND; + } + else + { + goto CODEC_NOT_FOUND; + } + } + } + return MM_ERROR_PLAYER_INVALID_STREAM; + } + break; + + case GST_STREAM_ERROR_CODEC_NOT_FOUND: + case GST_STREAM_ERROR_TYPE_NOT_FOUND: + case GST_STREAM_ERROR_WRONG_TYPE: + return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT; + + case GST_STREAM_ERROR_FAILED: + { + /* Decoder Custom Message */ + if ( strstr(error->message, "ongoing") ) + { + if ( strncasecmp(klass, "audio", 5) ) + { + if ( ( player->can_support_codec & FOUND_PLUGIN_VIDEO ) ) + { + debug_log("Video can keep playing.\n"); + return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND; + } + else + { + goto CODEC_NOT_FOUND; + } + + } + else if ( strncasecmp(klass, "video", 5) ) + { + if ( ( player->can_support_codec & FOUND_PLUGIN_AUDIO ) ) + { + debug_log("Audio can keep playing.\n"); + return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND; + } + else + { + goto CODEC_NOT_FOUND; + } + } + } + return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT; + } + break; + + case GST_STREAM_ERROR_DECRYPT: + case GST_STREAM_ERROR_DECRYPT_NOKEY: + { + debug_error("decryption error, [%s] failed, reason : [%s]\n", src_element_name, error->message); + + if ( strstr(error->message, "rights expired") ) + { + return MM_ERROR_PLAYER_DRM_EXPIRED; + } + else if ( strstr(error->message, "no rights") ) + { + return MM_ERROR_PLAYER_DRM_NO_LICENSE; + } + else if ( strstr(error->message, "has future rights") ) + { + return MM_ERROR_PLAYER_DRM_FUTURE_USE; + } + else if ( strstr(error->message, "opl violation") ) + { + return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION; + } + return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED; + } + break; + + default: + break; + } + + MMPLAYER_FLEAVE(); + + return MM_ERROR_PLAYER_INVALID_STREAM; + +INTERNAL_ERROR: + return MM_ERROR_PLAYER_INTERNAL; + +CODEC_NOT_FOUND: + debug_log("not found any available codec. Player should be destroyed.\n"); + return MM_ERROR_PLAYER_CODEC_NOT_FOUND; +} + +int _mmplayer_set_shm_stream_path(MMHandleType hplayer, const char *path) +{ + mm_player_t* player = (mm_player_t*) hplayer; + int result; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + return_val_if_fail(path, MM_ERROR_INVALID_ARGUMENT); + + result = mm_attrs_set_string_by_name(player->attrs, "shm_stream_path", path) + + MMPLAYER_FLEAVE(); + return result; +} \ No newline at end of file diff --git a/src/mm_player_es.c b/src/mm_player_es.c deleted file mode 100755 index 21efc6c..0000000 --- a/src/mm_player_es.c +++ /dev/null @@ -1,717 +0,0 @@ -/* - * libmm-player - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , heechul jeon , - * YoungHwan An , Eunhae Choi - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/*=========================================================================================== -| | -| INCLUDE FILES | -| | -========================================================================================== */ -#include "mm_player_es.h" -#include "mm_player_utils.h" -#include "mm_player_internal.h" - -#include - -/*--------------------------------------------------------------------------- -| LOCAL VARIABLE DEFINITIONS for internal | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| LOCAL FUNCTION PROTOTYPES: | ----------------------------------------------------------------------------*/ -static int _parse_media_format (MMPlayerVideoStreamInfo * video, MMPlayerAudioStreamInfo * audio, media_format_h format); -static int _convert_media_format_video_mime_to_str (MMPlayerVideoStreamInfo * video, media_format_mimetype_e mime); -static int _convert_media_format_audio_mime_to_str (MMPlayerAudioStreamInfo * audio, media_format_mimetype_e mime); - -/*=========================================================================================== -| | -| FUNCTION DEFINITIONS | -| | -========================================================================================== */ - -static int -_convert_media_format_video_mime_to_str (MMPlayerVideoStreamInfo * video, - media_format_mimetype_e mime) -{ - return_val_if_fail (video, MM_ERROR_INVALID_ARGUMENT); - - switch (mime) { - case MEDIA_FORMAT_MPEG4_SP: - video->mime = g_strdup ("video/mpeg"); - video->version = 4; - break; - case MEDIA_FORMAT_H264_SP: - case MEDIA_FORMAT_H264_MP: - case MEDIA_FORMAT_H264_HP: - video->mime = g_strdup ("video/x-h264"); - break; - default: - video->mime = g_strdup ("unknown"); - break; - } - - return MM_ERROR_NONE; -} - -static int -_convert_media_format_audio_mime_to_str (MMPlayerAudioStreamInfo * audio, - media_format_mimetype_e mime) -{ - return_val_if_fail (audio, MM_ERROR_INVALID_ARGUMENT); - - switch (mime) { - case MEDIA_FORMAT_AAC: - audio->mime = g_strdup ("audio/mpeg"); - audio->version = 2; - break; - default: - audio->mime = g_strdup ("unknown"); - break; - } - - return MM_ERROR_NONE; -} - -static int -_parse_media_format (MMPlayerVideoStreamInfo * video, - MMPlayerAudioStreamInfo * audio, media_format_h format) -{ - if (audio) { - media_format_mimetype_e mime; - int channel; - int samplerate; - int avg_bps; - - if (media_format_get_audio_info (format, &mime, &channel, &samplerate, NULL, - &avg_bps) != MEDIA_FORMAT_ERROR_NONE) { - debug_error ("media_format_get_audio_info failed"); - return MM_ERROR_PLAYER_INTERNAL; - } - - _convert_media_format_audio_mime_to_str (audio, mime); - audio->sample_rate = samplerate; - audio->channels = channel; -//video->user_info = ; - } - - if (video) { - media_format_mimetype_e mime; - int width; - int height; - int avg_bps; - - if (media_format_get_video_info (format, &mime, &width, &height, &avg_bps, - NULL) != MEDIA_FORMAT_ERROR_NONE) { - debug_error ("media_format_get_video_info failed"); - return MM_ERROR_PLAYER_INTERNAL; - } - - _convert_media_format_video_mime_to_str (video, mime); - video->width = width; - video->height = height; - } - - return MM_ERROR_NONE; -} - -static gboolean -_mmplayer_update_video_info(MMHandleType hplayer, media_format_h fmt) -{ - mm_player_t *player = (mm_player_t *) hplayer; - gboolean ret = FALSE; - GstStructure *str = NULL; - media_format_mimetype_e mimetype = 0; - gint cur_width = 0, width = 0; - gint cur_height = 0, height = 0; - - MMPLAYER_FENTER (); - - return_val_if_fail (player, FALSE); - return_val_if_fail (fmt, FALSE); - - if (player->v_stream_caps) - { - str = gst_caps_get_structure (player->v_stream_caps, 0); - if ( !gst_structure_get_int (str, "width", &cur_width)) - { - debug_log ("missing 'width' field in video caps"); - } - - if ( !gst_structure_get_int (str, "height", &cur_height)) - { - debug_log ("missing 'height' field in video caps"); - } - - media_format_get_video_info(fmt, &mimetype, &width, &height, NULL, NULL); - if ((cur_width != width) || (cur_height != height)) - { - debug_warning ("resolution is changed %dx%d -> %dx%d", - cur_width, cur_height, width, height); - _mmplayer_set_video_info(hplayer, fmt); - ret = TRUE; - } - } - - MMPLAYER_FLEAVE (); - return ret; -} - - -int -_mmplayer_set_media_stream_buffer_status_cb(MMHandleType hplayer, - MMPlayerStreamType type, - mm_player_media_stream_buffer_status_callback callback, - void *user_param) -{ - mm_player_t *player = (mm_player_t *) hplayer; - - MMPLAYER_FENTER (); - - return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - if ((type < MM_PLAYER_STREAM_TYPE_DEFAULT) || (type > MM_PLAYER_STREAM_TYPE_TEXT)) - return MM_ERROR_INVALID_ARGUMENT; - - if (player->media_stream_buffer_status_cb[type]) - { - if (!callback) - { - debug_log ("[type:%d] will be clear.\n", type); - } - else - { - debug_log ("[type:%d] will be overwritten.\n", type); - } - } - - player->media_stream_buffer_status_cb[type] = callback; - player->buffer_cb_user_param = user_param; - - debug_log ("player handle %p, type %d, callback %p\n", player, type, - player->media_stream_buffer_status_cb[type]); - - MMPLAYER_FLEAVE (); - - return MM_ERROR_NONE; -} - -int -_mmplayer_set_media_stream_seek_data_cb(MMHandleType hplayer, - MMPlayerStreamType type, - mm_player_media_stream_seek_data_callback callback, - void *user_param) -{ - mm_player_t *player = (mm_player_t *) hplayer; - - MMPLAYER_FENTER (); - - return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - if ((type < MM_PLAYER_STREAM_TYPE_DEFAULT) || (type > MM_PLAYER_STREAM_TYPE_TEXT)) - return MM_ERROR_INVALID_ARGUMENT; - - if (player->media_stream_seek_data_cb[type]) - { - if (!callback) - { - debug_log ("[type:%d] will be clear.\n", type); - } - else - { - debug_log ("[type:%d] will be overwritten.\n", type); - } - } - - player->media_stream_seek_data_cb[type] = callback; - player->buffer_cb_user_param = user_param; - - debug_log ("player handle %p, type %d, callback %p\n", player, type, - player->media_stream_seek_data_cb[type]); - - MMPLAYER_FLEAVE (); - - return MM_ERROR_NONE; -} - -int -_mmplayer_set_media_stream_max_size(MMHandleType hplayer, MMPlayerStreamType type, guint64 max_size) -{ - mm_player_t *player = (mm_player_t *) hplayer; - - MMPLAYER_FENTER (); - - return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - if ((type < MM_PLAYER_STREAM_TYPE_DEFAULT) || (type > MM_PLAYER_STREAM_TYPE_TEXT)) - return MM_ERROR_INVALID_ARGUMENT; - - player->media_stream_buffer_max_size[type] = max_size; - - debug_log ("type %d, max_size %llu\n", - type, player->media_stream_buffer_max_size[type]); - - MMPLAYER_FLEAVE (); - - return MM_ERROR_NONE; -} - -int -_mmplayer_get_media_stream_max_size(MMHandleType hplayer, MMPlayerStreamType type, guint64 *max_size) -{ - mm_player_t *player = (mm_player_t *) hplayer; - - MMPLAYER_FENTER (); - - return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail (max_size, MM_ERROR_INVALID_ARGUMENT); - - if ((type < MM_PLAYER_STREAM_TYPE_DEFAULT) || (type > MM_PLAYER_STREAM_TYPE_TEXT)) - return MM_ERROR_INVALID_ARGUMENT; - - *max_size = player->media_stream_buffer_max_size[type]; - - MMPLAYER_FLEAVE (); - - return MM_ERROR_NONE; -} - -int -_mmplayer_set_media_stream_min_percent(MMHandleType hplayer, MMPlayerStreamType type, guint min_percent) -{ - mm_player_t *player = (mm_player_t *) hplayer; - - MMPLAYER_FENTER (); - - return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - if ((type < MM_PLAYER_STREAM_TYPE_DEFAULT) || (type > MM_PLAYER_STREAM_TYPE_TEXT)) - return MM_ERROR_INVALID_ARGUMENT; - - player->media_stream_buffer_min_percent[type] = min_percent; - - debug_log ("type %d, min_per %u\n", - type, player->media_stream_buffer_min_percent[type]); - - MMPLAYER_FLEAVE (); - - return MM_ERROR_NONE; -} - -int -_mmplayer_get_media_stream_min_percent(MMHandleType hplayer, MMPlayerStreamType type, guint *min_percent) -{ - mm_player_t *player = (mm_player_t *) hplayer; - - MMPLAYER_FENTER (); - - return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail (min_percent, MM_ERROR_INVALID_ARGUMENT); - - if ((type < MM_PLAYER_STREAM_TYPE_DEFAULT) || (type > MM_PLAYER_STREAM_TYPE_TEXT)) - return MM_ERROR_INVALID_ARGUMENT; - - *min_percent = player->media_stream_buffer_min_percent[type]; - - MMPLAYER_FLEAVE (); - - return MM_ERROR_NONE; -} - -int -_mmplayer_submit_packet (MMHandleType hplayer, media_packet_h packet) -{ - int ret = MM_ERROR_NONE; - GstBuffer *_buffer = NULL; - mm_player_t *player = (mm_player_t *) hplayer; - guint8 *buf = NULL; - MMPlayerTrackType streamtype = MM_PLAYER_TRACK_TYPE_AUDIO; - media_format_h fmt = NULL; - bool flag = FALSE; - - return_val_if_fail (packet, MM_ERROR_INVALID_ARGUMENT); - return_val_if_fail ( player && - player->pipeline && - player->pipeline->mainbin && - player->pipeline->mainbin[MMPLAYER_M_SRC].gst, - MM_ERROR_PLAYER_INTERNAL ); - - /* get stream type if audio or video */ - media_packet_is_audio (packet, &flag); - if (flag) { - streamtype = MM_PLAYER_TRACK_TYPE_AUDIO; - } else { - media_packet_is_video (packet, &flag); - - if (flag) - streamtype = MM_PLAYER_TRACK_TYPE_VIDEO; - else - streamtype = MM_PLAYER_TRACK_TYPE_TEXT; - } - - /* get data */ - media_packet_get_buffer_data_ptr (packet, (void **) &buf); - - if (buf != NULL) { - GstMapInfo buff_info = GST_MAP_INFO_INIT; - uint64_t size = 0; - uint64_t pts = 0; - - /* get size */ - media_packet_get_buffer_size (packet, &size); - - _buffer = gst_buffer_new_and_alloc (size); - if (!_buffer) { - debug_error("failed to allocate memory for push buffer\n"); - return MM_ERROR_PLAYER_NO_FREE_SPACE; - } - - if (gst_buffer_map (_buffer, &buff_info, GST_MAP_READWRITE)) { - - memcpy (buff_info.data, buf, size); - buff_info.size = size; - - gst_buffer_unmap (_buffer, &buff_info); - } - - /* get pts */ - media_packet_get_pts (packet, &pts); - GST_BUFFER_PTS (_buffer) = (GstClockTime) (pts * 1000000); - - if (streamtype == MM_PLAYER_TRACK_TYPE_AUDIO) { -#if 0 // TO CHECK : has gone (set to pad) - if (GST_CAPS_IS_SIMPLE (player->a_stream_caps)) - GST_BUFFER_CAPS (_buffer) = gst_caps_copy (player->a_stream_caps); - else - debug_error ("External Demuxer case: Audio Buffer Caps not set."); -#endif - if (player->pipeline->mainbin[MMPLAYER_M_2ND_SRC].gst) - gst_app_src_push_buffer (GST_APP_SRC (player->pipeline->mainbin[MMPLAYER_M_2ND_SRC].gst), _buffer); - else if (g_strrstr (GST_ELEMENT_NAME (player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "audio_appsrc")) - gst_app_src_push_buffer (GST_APP_SRC (player->pipeline->mainbin[MMPLAYER_M_SRC].gst), _buffer); - } else if (streamtype == MM_PLAYER_TRACK_TYPE_VIDEO) { -#if 0 // TO CHECK : has gone (set to pad) - if (GST_CAPS_IS_SIMPLE (player->v_stream_caps)) - GST_BUFFER_CAPS (_buffer) = gst_caps_copy (player->v_stream_caps); - else - debug_error ("External Demuxer case: Video Buffer Caps not set."); -#endif - /* get format to check video format */ - media_packet_get_format (packet, &fmt); - if (fmt) - { - gboolean ret = FALSE; - ret = _mmplayer_update_video_info(hplayer, fmt); - if (ret) - { - g_object_set(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), - "caps", player->v_stream_caps, NULL); - } - } - - gst_app_src_push_buffer (GST_APP_SRC (player->pipeline->mainbin[MMPLAYER_M_SRC].gst), _buffer); - } else if (streamtype == MM_PLAYER_TRACK_TYPE_TEXT) { -#if 0 // TO CHECK : has gone (set to pad) - if (GST_CAPS_IS_SIMPLE (player->s_stream_caps)) - GST_BUFFER_CAPS (_buffer) = gst_caps_copy (player->s_stream_caps); - else - debug_error ("External Demuxer case: Subtitle Buffer Caps not set."); -#endif - gst_app_src_push_buffer (GST_APP_SRC (player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst), _buffer); - } else { - debug_error ("Not a valid packet from external demux"); - return FALSE; - } - } else { - debug_log ("Sending EOS on pipeline..."); - if (streamtype == MM_PLAYER_TRACK_TYPE_AUDIO) { - if (player->pipeline->mainbin[MMPLAYER_M_2ND_SRC].gst) - g_signal_emit_by_name (player->pipeline-> - mainbin[MMPLAYER_M_2ND_SRC].gst, "end-of-stream", &ret); - else - g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, - "end-of-stream", &ret); - } else if (streamtype == MM_PLAYER_TRACK_TYPE_VIDEO) { - g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, - "end-of-stream", &ret); - } else if (streamtype == MM_PLAYER_TRACK_TYPE_TEXT) { - g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst, - "end-of-stream", &ret); - } - } - - if (MMPLAYER_PENDING_STATE (player) == MM_PLAYER_STATE_PLAYING) { - //ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING); - } - - return ret; -} - -int -_mmplayer_video_caps_new (MMHandleType hplayer, MMPlayerVideoStreamInfo * video, - const char *fieldname, ...) -{ - int cap_size; - GstCaps *caps = NULL; - GstStructure *structure = NULL; - va_list var_args; - mm_player_t *player = MM_PLAYER_CAST (hplayer); - - MMPLAYER_FENTER (); - return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail (video, MM_ERROR_PLAYER_NOT_INITIALIZED); - - debug_log ("width=%d height=%d framerate num=%d, den=%d", - video->width, video->height, video->framerate_num, video->framerate_den); - - caps = gst_caps_new_simple (video->mime, - "width", G_TYPE_INT, video->width, - "height", G_TYPE_INT, video->height, - "framerate", GST_TYPE_FRACTION, video->framerate_num, video->framerate_den, NULL); - - for (cap_size = 0; cap_size < gst_caps_get_size (caps); cap_size++) { - va_start (var_args, fieldname); - structure = gst_caps_get_structure (caps, cap_size); - gst_structure_set_valist (structure, fieldname, var_args); - va_end (var_args); - } - - if (video->extradata_size) { - GstBuffer *buf = NULL; - GstMapInfo buff_info = GST_MAP_INFO_INIT; - - buf = gst_buffer_new_and_alloc (video->extradata_size); - - if (gst_buffer_map (buf, &buff_info, GST_MAP_READ)) { - memcpy (buff_info.data, video->codec_extradata, video->extradata_size); - buff_info.size = video->extradata_size; - gst_buffer_unmap (buf, &buff_info); - } - - gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, buf, NULL); - gst_buffer_unref (buf); - } - - if (player->v_stream_caps) - { - debug_warning ("caps will be updated "); - - gst_caps_unref(player->v_stream_caps); - player->v_stream_caps = NULL; - } - - player->v_stream_caps = gst_caps_copy (caps); - MMPLAYER_LOG_GST_CAPS_TYPE (player->v_stream_caps); - gst_caps_unref (caps); - - MMPLAYER_FLEAVE (); - - return MM_ERROR_NONE; -} - -int -_mmplayer_set_video_info (MMHandleType hplayer, media_format_h format) -{ - mm_player_t *player = MM_PLAYER_CAST (hplayer); - MMPlayerVideoStreamInfo video = { 0, }; - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER (); - - return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - ret = _parse_media_format (&video, NULL, format); - if(ret != MM_ERROR_NONE) - return ret; - - if (strstr (video.mime, "video/mpeg")) { - _mmplayer_video_caps_new (hplayer, &video, - "mpegversion", G_TYPE_INT, video.version, - "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); - } else if (strstr (video.mime, "video/x-h264")) { - //if (info.colordepth) - { - // _mmplayer_video_caps_new(hplayer, &info, - // "colordepth", G_TYPE_INT, info.colordepth, NULL); - } - //else - { - _mmplayer_video_caps_new (hplayer, &video, - "stream-format", G_TYPE_STRING, "byte-stream", - "alignment", G_TYPE_STRING, "au", NULL); - } - } -#if 0 - else if (strstr (info->mime, "video/x-wmv")) { - _mmplayer_video_caps_new (hplayer, &info, - "wmvversion", G_TYPE_INT, info.version, NULL); - } else if (strstr (info.mime, "video/x-pn-realvideo")) { - _mmplayer_video_caps_new (hplayer, &info, - "rmversion", G_TYPE_INT, info.version, NULL); - } else if (strstr (info.mime, "video/x-msmpeg")) { - _mmplayer_video_caps_new (hplayer, &info, - "msmpegversion", G_TYPE_INT, info.version, NULL); - } else if (strstr (info.mime, "video/x-h265")) { - if (info.colordepth) { - _mmplayer_video_caps_new (hplayer, &info, - "colordepth", G_TYPE_INT, info.colordepth, NULL); - } else { - _mmplayer_video_caps_new (hplayer, &info, NULL); - } - } else { - _mmplayer_video_caps_new (hplayer, &info, NULL); - } -#endif - g_free ((char *) video.mime); - - MMPLAYER_FLEAVE (); - - return MM_ERROR_NONE; -} - -int -_mmplayer_set_audio_info (MMHandleType hplayer, media_format_h format) -{ - mm_player_t *player = MM_PLAYER_CAST (hplayer); - GstCaps *caps = NULL; - MMPlayerAudioStreamInfo audio = { 0, }; - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER (); - - return_val_if_fail (hplayer, MM_ERROR_PLAYER_NOT_INITIALIZED); - - ret = _parse_media_format (NULL, &audio, format); - if(ret != MM_ERROR_NONE) - return ret; - - audio.user_info = 0; //test - - debug_log ("set audio player[%p] info [%p] version=%d rate=%d channel=%d", - player, audio, audio.version, audio.sample_rate, audio.channels); - - if (strstr (audio.mime, "audio/mpeg")) { - if (audio.version == 1) { // mp3 - caps = gst_caps_new_simple ("audio/mpeg", - "channels", G_TYPE_INT, audio.channels, - "rate", G_TYPE_INT, audio.sample_rate, - "mpegversion", G_TYPE_INT, audio.version, - "layer", G_TYPE_INT, audio.user_info, NULL); - } else { // aac - gchar *format = NULL; - - if (audio.user_info == 0) - format = g_strdup ("raw"); - else if (audio.user_info == 1) - format = g_strdup ("adts"); - else if (audio.user_info == 2) - format = g_strdup ("adif"); - - caps = gst_caps_new_simple ("audio/mpeg", - "channels", G_TYPE_INT, audio.channels, - "rate", G_TYPE_INT, audio.sample_rate, - "mpegversion", G_TYPE_INT, audio.version, - "stream-format", G_TYPE_STRING, format, NULL); - - g_free (format); - format = NULL; - } - } -#if 0 - else if (strstr (audio.mime, "audio/x-raw-int")) { - caps = gst_caps_new_simple ("audio/x-raw-int", - "width", G_TYPE_INT, audio.width, - "depth", G_TYPE_INT, audio.depth, - "endianness", G_TYPE_INT, audio.endianness, - "signed", G_TYPE_BOOLEAN, audio.signedness, - "channels", G_TYPE_INT, audio.channels, - "rate", G_TYPE_INT, audio.sample_rate, NULL); - } else { - caps = gst_caps_new_simple (audio.mime, - "channels", G_TYPE_INT, audio.channels, - "rate", G_TYPE_INT, audio.sample_rate, NULL); - } -#endif - - if (audio.extradata_size) { - GstBuffer *buf = NULL; - GstMapInfo buff_info = GST_MAP_INFO_INIT; - - buf = gst_buffer_new_and_alloc (audio.extradata_size); - - if (gst_buffer_map (buf, &buff_info, GST_MAP_READ)) { - memcpy (buff_info.data, audio.codec_extradata, audio.extradata_size); - gst_buffer_unmap (buf, &buff_info); - } - - gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, buf, NULL); - gst_buffer_unref (buf); - } - - g_free ((char *) audio.mime); - - player->a_stream_caps = gst_caps_copy (caps); - gst_caps_unref (caps); - - MMPLAYER_FLEAVE (); - - return MM_ERROR_NONE; -} - -int -_mmplayer_set_subtitle_info (MMHandleType hplayer, - MMPlayerSubtitleStreamInfo * subtitle) -{ -#if 0 //todo - - mm_player_t *player = MM_PLAYER_CAST (hplayer); - GstCaps *caps = NULL; - - MMPLAYER_FENTER (); - - return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail (info, MM_ERROR_PLAYER_NOT_INITIALIZED); - - debug_log ("set subtitle player[%p] info [%p]", player, info); - - - caps = gst_caps_new_simple (info->mime, NULL, NULL); // TO CHECK - if (NULL == caps) - return FALSE; - - if (strstr (info->mime, "application/x-xsub")) { - gst_caps_set_simple (caps, "codec_tag", G_TYPE_UINT, info->codec_tag, NULL); - } else if (strstr (info->mime, "application/x-smpte-text")) { - if (info->context) { - gst_caps_set_simple (caps, "ttml_priv_data", G_TYPE_POINTER, - info->context, NULL); - } - } - - player->s_stream_caps = gst_caps_copy (caps); - - gst_caps_unref (caps); -#endif - - MMPLAYER_FLEAVE (); - - return MM_ERROR_NONE; -} diff --git a/src/mm_player_pd.c b/src/mm_player_pd.c deleted file mode 100644 index 09f16cc..0000000 --- a/src/mm_player_pd.c +++ /dev/null @@ -1,467 +0,0 @@ -/* - * libmm-player - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , naveen cherukuri , - * YeJin Cho , YoungHwan An - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -#include -#include -#include "mm_player_pd.h" -#include "mm_player_utils.h" -#include "mm_player_priv.h" - -/*--------------------------------------------------------------------------------------- -| LOCAL FUNCTION PROTOTYPES: | ----------------------------------------------------------------------------------------*/ - -/* It's callback to process whenever there is some changes in PD downloader. */ -static gboolean __pd_downloader_callback(GstBus *bus, GstMessage *msg, gpointer data); - -/* This function posts messages to application. */ -/* Currently, MM_MESSAGE_PD_DOWNLOADER_START and MM_MESSAGE_PD_DOWNLOADER_END are used. */ -static gboolean __pd_downloader_post_message(mm_player_t * player, enum MMMessageType msgtype, MMMessageParamType* param); - -/*======================================================================================= -| FUNCTION DEFINITIONS | -=======================================================================================*/ -static gboolean -__pd_downloader_callback(GstBus *bus, GstMessage *msg, gpointer data) -{ - mm_player_t * player = NULL; - mm_player_pd_t *pd = NULL; - gboolean bret = TRUE; - - MMPLAYER_FENTER(); - - /* chech player handle */ - return_val_if_fail ( data, MM_ERROR_INVALID_ARGUMENT ); - - player = MM_PLAYER_CAST((MMHandleType)data); - - /* get PD downloader handle */ - pd = MM_PLAYER_GET_PD((MMHandleType)data); - - return_val_if_fail ( pd, MM_ERROR_INVALID_ARGUMENT ); - -// g_print("%s\n", GST_MESSAGE_TYPE_NAME(msg)); - - switch ( GST_MESSAGE_TYPE( msg ) ) - { - case GST_MESSAGE_EOS: - { - debug_log("PD Downloader EOS received....\n"); - - g_object_set (G_OBJECT (pd->playback_pipeline_src), "eos", TRUE, NULL); - - /* notify application that download is completed */ - __pd_downloader_post_message(player, MM_MESSAGE_PD_DOWNLOADER_END, NULL); - - #ifdef PD_SELF_DOWNLOAD - _mmplayer_unrealize_pd_downloader ((MMHandleType)data); - #endif - } - break; - - case GST_MESSAGE_ERROR: - { - GError *error = NULL; - gchar* debug = NULL; - GstMessage *new_msg = NULL; - - /* get error code */ - gst_message_parse_error( msg, &error, &debug ); - debug_error ("GST_MESSAGE_ERROR = %s\n", debug); - - new_msg = gst_message_new_error (GST_OBJECT_CAST (pd->playback_pipeline_src), error, debug); - - /* notify application that pd has any error */ - gst_element_post_message (pd->playback_pipeline_src, new_msg); - - _mmplayer_unrealize_pd_downloader ((MMHandleType)data); - MMPLAYER_FREEIF(debug); - g_error_free( error); - } - break; - - case GST_MESSAGE_WARNING: - { - char* debug = NULL; - GError* error = NULL; - - gst_message_parse_warning(msg, &error, &debug); - debug_warning("warning : %s\n", error->message); - debug_warning("debug : %s\n", debug); - - MMPLAYER_FREEIF(debug); - g_error_free( error); - } - break; - - case GST_MESSAGE_STATE_CHANGED: - { - GstState old_state, new_state; - gchar *src_name; - - /* get old and new state */ - gst_message_parse_state_changed (msg, &old_state, &new_state, NULL); - - if (old_state == new_state) - break; - - /* we only care about pipeline state changes */ - if (GST_MESSAGE_SRC (msg) != GST_OBJECT (pd->downloader_pipeline)) - break; - - src_name = gst_object_get_name (msg->src); - debug_log ("%s changed state from %s to %s", src_name, - gst_element_state_get_name (old_state), - gst_element_state_get_name (new_state)); - g_free (src_name); - - switch(new_state) - { - case GST_STATE_VOID_PENDING: - case GST_STATE_NULL: - case GST_STATE_READY: - case GST_STATE_PAUSED: - break; - - case GST_STATE_PLAYING: - /* notify application that download is stated */ - __pd_downloader_post_message(player, MM_MESSAGE_PD_DOWNLOADER_START, NULL); - break; - - default: - break; - } - } - break; - - case GST_MESSAGE_DURATION: - { - gint64 size = 0LL; - - /* get total size of download file, (bytes) */ - if ( ! gst_element_query_duration( pd->downloader_pipeline, GST_FORMAT_BYTES, &size ) ) - { - GError *err = NULL; - GstMessage *new_msg = NULL; - - err = g_error_new (GST_STREAM_ERROR, GST_STREAM_ERROR_FAILED, "can't get total size"); - new_msg = gst_message_new_error (GST_OBJECT_CAST (pd->playback_pipeline_src), err, NULL); - gst_element_post_message (pd->playback_pipeline_src, new_msg); - - g_error_free (err); - - // TODO: check if playback pipeline is closed well or not - g_object_set (G_OBJECT (pd->playback_pipeline_src), "eos", TRUE, NULL); - - _mmplayer_unrealize_pd_downloader ((MMHandleType)data); - - debug_error("failed to query total size for download\n"); - break; - } - - pd->total_size = size; - - debug_log("PD total size : %lld bytes\n", size); - } - break; - - default: - debug_warning("unhandled message\n"); - break; - } - - MMPLAYER_FLEAVE(); - - return bret; -} - - -gboolean __pd_downloader_post_message(mm_player_t * player, enum MMMessageType msgtype, MMMessageParamType* param) -{ - MMPLAYER_FENTER(); - - return_val_if_fail( player, FALSE ); - - if ( !player->pd_msg_cb ) - { - debug_warning("no msg callback. can't post\n"); - return FALSE; - } - - player->pd_msg_cb(msgtype, param, player->pd_msg_cb_param); - - MMPLAYER_FLEAVE(); - - return TRUE; -} - - -gboolean _mmplayer_get_pd_downloader_status(MMHandleType handle, guint64 *current_pos, guint64 *total_size) -{ - MMPLAYER_FENTER(); - - mm_player_pd_t * pd = NULL; - guint64 bytes = 0; - - return_val_if_fail(handle, MM_ERROR_INVALID_ARGUMENT); - - pd = MM_PLAYER_GET_PD(handle); - - return_val_if_fail(pd, MM_ERROR_INVALID_ARGUMENT); - return_val_if_fail(pd->downloader_pipeline, MM_ERROR_PLAYER_INVALID_STATE); - - if ( !pd->total_size ) - { - debug_warning("not ready to get total size\n"); - return FALSE; - } - - g_object_get(pd->downloader_sink, "current-bytes", &bytes, NULL); - - debug_log("PD status : %lld / %lld\n", bytes, pd->total_size); - - *current_pos = bytes; - *total_size = pd->total_size; - - MMPLAYER_FLEAVE(); - - return TRUE; -} - - -mm_player_pd_t * _mmplayer_create_pd_downloader() -{ - MMPLAYER_FENTER(); - - mm_player_pd_t * pd = NULL; - - /* create PD handle */ - pd = (mm_player_pd_t *) malloc (sizeof (mm_player_pd_t)); - if ( !pd ) - { - debug_error ("Failed to create pd downloader handle...\n"); - return FALSE; - } - memset( pd, 0, sizeof (mm_player_pd_t)); - - MMPLAYER_FLEAVE(); - - return pd; -} - - -gboolean _mmplayer_destroy_pd_downloader (MMHandleType handle) -{ - MMPLAYER_FENTER(); - - mm_player_pd_t * pd = NULL; - - return_val_if_fail ( handle, MM_ERROR_INVALID_ARGUMENT ); - - pd = MM_PLAYER_GET_PD(handle); - - if (pd && pd->downloader_pipeline) - _mmplayer_unrealize_pd_downloader (handle); - - /* release PD handle */ - MMPLAYER_FREEIF(pd); - - MMPLAYER_FLEAVE(); - - return TRUE; -} - - -gboolean _mmplayer_realize_pd_downloader (MMHandleType handle, gchar *src_uri, gchar *dst_uri, GstElement *pushsrc) -{ - MMPLAYER_FENTER(); - - mm_player_pd_t * pd = NULL; - - return_val_if_fail ( handle, MM_ERROR_INVALID_ARGUMENT ); - return_val_if_fail ( src_uri, MM_ERROR_INVALID_ARGUMENT ); - return_val_if_fail ( dst_uri, MM_ERROR_INVALID_ARGUMENT ); - return_val_if_fail ( pushsrc, MM_ERROR_INVALID_ARGUMENT ); - - pd = MM_PLAYER_GET_PD(handle); - - /* initialize */ - pd->path_read_from = g_strdup (src_uri); - pd->location_to_save = g_strdup (dst_uri); - pd->playback_pipeline_src = pushsrc; - pd->total_size = 0LL; - - MMPLAYER_FLEAVE(); - - return TRUE; -} - - -gboolean _mmplayer_start_pd_downloader (MMHandleType handle) -{ - GstBus* bus = NULL; - gboolean bret = FALSE; - GstStateChangeReturn sret = GST_STATE_CHANGE_SUCCESS; - GstState cur_state; - GstState pending_state; - - MMPLAYER_FENTER(); - - mm_player_pd_t * pd = NULL; - - return_val_if_fail ( handle, MM_ERROR_INVALID_ARGUMENT ); - - pd = MM_PLAYER_GET_PD(handle); - - /* pipeline */ - pd->downloader_pipeline = gst_pipeline_new ("PD Downloader"); - if (NULL == pd->downloader_pipeline) - { - debug_error ("Can't create PD download pipeline..."); - return FALSE; - } - - /* source */ - pd->downloader_src = gst_element_factory_make ("souphttpsrc", "PD HTTP download source"); - if (NULL == pd->downloader_src) - { - debug_error ("Can't create PD download src..."); - return FALSE; - } - - /* queue */ - pd->downloader_queue = gst_element_factory_make ("queue", "PD download queue"); - if (NULL == pd->downloader_queue) - { - debug_error ("Can't create PD download queue..."); - return FALSE; - } - - /* filesink */ - pd->downloader_sink = gst_element_factory_make ("filesink", "PD download sink"); - if (NULL == pd->downloader_sink) - { - debug_error ("Can't create PD download sink..."); - return FALSE; - } - - g_object_set(pd->downloader_sink, "sync", FALSE, NULL); - - /* Add to bin and link */ - gst_bin_add_many (GST_BIN (pd->downloader_pipeline), - pd->downloader_src, pd->downloader_queue, pd->downloader_sink, - NULL); - - bret = gst_element_link_many (pd->downloader_src, pd->downloader_queue, pd->downloader_sink, NULL); - if (FALSE == bret) - { - debug_error ("Can't link elements src and sink..."); - return FALSE; - } - - /* Get Bus and set callback to watch */ - bus = gst_pipeline_get_bus (GST_PIPELINE (pd->downloader_pipeline)); - gst_bus_add_watch (bus, __pd_downloader_callback, (gpointer)handle); - gst_object_unref (bus); - - /* Set URI on HTTP source */ - g_object_set (G_OBJECT (pd->downloader_src), "location", pd->path_read_from, NULL); - - /* set file download location on filesink*/ - g_object_set (G_OBJECT (pd->downloader_sink), "location", pd->location_to_save, NULL); - - secure_debug_log ("src location = %s, save location = %s\n", pd->path_read_from, pd->location_to_save); - - /* Start to download */ - sret = gst_element_set_state (pd->downloader_pipeline, GST_STATE_PLAYING); - if (GST_STATE_CHANGE_FAILURE == sret) - { - debug_error ("PD download pipeline failed to go to PLAYING state..."); - return FALSE; - } - - debug_log ("set_state :: sret = %d\n", sret); - - sret = gst_element_get_state (pd->downloader_pipeline, &cur_state, &pending_state, GST_CLOCK_TIME_NONE); - if (GST_STATE_CHANGE_FAILURE == sret) - { - debug_error ("PD download pipeline failed to do get_state..."); - return FALSE; - } - - debug_log ("get-state :: sret = %d\n", sret); - - MMPLAYER_FLEAVE(); - - return TRUE; -} - - -gboolean _mmplayer_unrealize_pd_downloader (MMHandleType handle) -{ - MMPLAYER_FENTER(); - - mm_player_pd_t * pd = NULL; - - return_val_if_fail ( handle, FALSE ); - - pd = MM_PLAYER_GET_PD(handle); - - return_val_if_fail ( pd && pd->downloader_pipeline, FALSE ); - - gst_element_set_state (pd->downloader_pipeline, GST_STATE_NULL); - gst_element_get_state (pd->downloader_pipeline, NULL, NULL, GST_CLOCK_TIME_NONE); - - gst_object_unref (G_OBJECT (pd->downloader_pipeline)); - pd->downloader_pipeline = NULL; - - /* free */ - MMPLAYER_FREEIF(pd->path_read_from); - MMPLAYER_FREEIF(pd->location_to_save); - - MMPLAYER_FLEAVE(); - - return TRUE; -} - - -gint _mm_player_set_pd_downloader_message_cb(MMHandleType handle, MMMessageCallback callback, gpointer user_param) -{ - MMPLAYER_FENTER(); - - mm_player_t * player = NULL; - - return_val_if_fail ( handle, MM_ERROR_INVALID_ARGUMENT ); - - player = MM_PLAYER_CAST((MMHandleType)handle); - - /* PD callback can be set as soon as player handle is created. - * So, player handle must have it. - */ - player->pd_msg_cb = callback; - player->pd_msg_cb_param = user_param; - - debug_log("msg_cb : %p msg_cb_param : %p\n", callback, user_param); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} diff --git a/src/mm_player_priv.c b/src/mm_player_priv.c deleted file mode 100755 index f950110..0000000 --- a/src/mm_player_priv.c +++ /dev/null @@ -1,17604 +0,0 @@ -/* - * libmm-player - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , YeJin Cho , - * Seungbae Shin , YoungHwan An - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/*=========================================================================================== -| | -| INCLUDE FILES | -| | -========================================================================================== */ -#include -#include -#include -#include -#ifdef HAVE_WAYLAND -#include -#endif -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "mm_player_priv.h" -#include "mm_player_ini.h" -#include "mm_player_attrs.h" -#include "mm_player_capture.h" -#include "mm_player_utils.h" -#include "mm_player_tracks.h" -#include - -#include -#include - -#define MM_SMOOTH_STREAMING - -/*=========================================================================================== -| | -| LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE | -| | -========================================================================================== */ - -/*--------------------------------------------------------------------------- -| GLOBAL CONSTANT DEFINITIONS: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| IMPORTED VARIABLE DECLARATIONS: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| IMPORTED FUNCTION DECLARATIONS: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| LOCAL #defines: | ----------------------------------------------------------------------------*/ -#define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0 -#define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0 - -#define MM_VOLUME_FACTOR_DEFAULT 1.0 -#define MM_VOLUME_FACTOR_MIN 0 -#define MM_VOLUME_FACTOR_MAX 1.0 - -#define MM_PLAYER_FADEOUT_TIME_DEFAULT 700000 // 700 msec - -#define MM_PLAYER_MPEG_VNAME "mpegversion" -#define MM_PLAYER_DIVX_VNAME "divxversion" -#define MM_PLAYER_WMV_VNAME "wmvversion" -#define MM_PLAYER_WMA_VNAME "wmaversion" - -#define DEFAULT_PLAYBACK_RATE 1.0 -#define PLAYBACK_RATE_EX_AUDIO_MIN 0.5 -#define PLAYBACK_RATE_EX_AUDIO_MAX 2.0 -#define PLAYBACK_RATE_EX_VIDEO_MIN 0.5 -#define PLAYBACK_RATE_EX_VIDEO_MAX 1.5 - -#define GST_QUEUE_DEFAULT_TIME 4 -#define GST_QUEUE_HLS_TIME 8 - -#define DEFAULT_AUDIO_CH 0 - -#define MMPLAYER_USE_FILE_FOR_BUFFERING(player) (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && (player->ini.http_file_buffer_path) && (strlen(player->ini.http_file_buffer_path) > 0) ) - -#define LAZY_PAUSE_TIMEOUT_MSEC 700 -#define MM_PLAYER_NAME "mmplayer" - -#define SMOOTH_STREAMING_DEMUX "mssdemux" -/* - * g_array_index(a,t,i) does not calculate gst private structure. - * It replaces the g_array_index(a,t,i) - */ -#define g_array_undef_struct_idx_p(a,t,i) ((t *)(void *)((a)->data + ((i) * (a)->len))) - -//#define ENABLE_DRMSRC - -/*--------------------------------------------------------------------------- -| LOCAL CONSTANT DEFINITIONS: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| LOCAL DATA TYPE DEFINITIONS: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| GLOBAL VARIABLE DEFINITIONS: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| LOCAL VARIABLE DEFINITIONS: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| LOCAL FUNCTION PROTOTYPES: | ----------------------------------------------------------------------------*/ -static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type); -static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player); -static int __mmplayer_gst_create_text_pipeline(mm_player_t* player); -static int __mmplayer_gst_create_subtitle_src(mm_player_t* player); -static int __mmplayer_gst_create_pipeline(mm_player_t* player); -static int __mmplayer_gst_destroy_pipeline(mm_player_t* player); -static int __mmplayer_gst_element_link_bucket(GList* element_bucket); - -static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data); -static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data); -static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data); -static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data); -static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data); -static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data); -static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data); -//static GValueArray* __mmplayer_gst_decode_autoplug_factories(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data); -static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data); -static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data); -static void __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data); -static GstElement * __mmplayer_create_decodebin(mm_player_t* player); -static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps); - -static void __mmplayer_typefind_have_type( GstElement *tf, guint probability, GstCaps *caps, gpointer data); -static gboolean __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps); -static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data); -static gboolean __mmplayer_is_midi_type(gchar* str_caps); -static gboolean __mmplayer_is_only_mp3_type (gchar *str_caps); -static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps); -//static void __mmplayer_check_video_zero_cpoy(mm_player_t* player, GstElementFactory* factory); - -static gboolean __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement, const char *padname, const GList *templlist); -static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data); -static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data); - -static void __mmplayer_gst_rtp_no_more_pads (GstElement *element, gpointer data); -//static void __mmplayer_gst_wfd_dynamic_pad (GstElement *element, GstPad *pad, gpointer data); -static void __mmplayer_gst_rtp_dynamic_pad (GstElement *element, GstPad *pad, gpointer data); -static gboolean __mmplayer_get_stream_service_type( mm_player_t* player ); -static gboolean __mmplayer_update_subtitle( GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data); - - -static void __mmplayer_init_factories(mm_player_t* player); -static void __mmplayer_release_factories(mm_player_t* player); -static void __mmplayer_release_misc(mm_player_t* player); -static void __mmplayer_release_misc_post(mm_player_t* player); -static gboolean __mmplayer_init_gstreamer(mm_player_t* player); - -static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg); -static gboolean __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg); - -int __mmplayer_switch_audio_sink (mm_player_t* player); -static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink); -static GstPadProbeReturn __mmplayer_audio_stream_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data); -static GstPadProbeReturn __mmplayer_video_stream_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data); -static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data); -static int __mmplayer_change_selector_pad (mm_player_t* player, MMPlayerTrackType type, int index); - -static gboolean __mmplayer_check_subtitle( mm_player_t* player ); -static gboolean __mmplayer_handle_gst_error ( mm_player_t* player, GstMessage * message, GError* error ); -static gboolean __mmplayer_handle_streaming_error ( mm_player_t* player, GstMessage * message ); -static void __mmplayer_handle_eos_delay( mm_player_t* player, int delay_in_ms ); -static void __mmplayer_cancel_eos_timer( mm_player_t* player ); -static gboolean __mmplayer_eos_timer_cb(gpointer u_data); -static gboolean __mmplayer_link_decoder( mm_player_t* player,GstPad *srcpad); -static gboolean __mmplayer_link_sink( mm_player_t* player,GstPad *srcpad); -static int __mmplayer_handle_missed_plugin(mm_player_t* player); -static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime); -static gboolean __mmplayer_configure_audio_callback(mm_player_t* player); -static void __mmplayer_add_sink( mm_player_t* player, GstElement* sink); -static void __mmplayer_del_sink( mm_player_t* player, GstElement* sink); -static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type); -static gpointer __mmplayer_next_play_thread(gpointer data); -static gpointer __mmplayer_repeat_thread(gpointer data); -static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag); - - -static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element); -static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data); -static void __mmplayer_release_dump_list (GList *dump_list); - -static int __gst_realize(mm_player_t* player); -static int __gst_unrealize(mm_player_t* player); -static int __gst_start(mm_player_t* player); -static int __gst_stop(mm_player_t* player); -static int __gst_pause(mm_player_t* player, gboolean async); -static int __gst_resume(mm_player_t* player, gboolean async); -static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate, - GstFormat format, GstSeekFlags flags, GstSeekType cur_type, - gint64 cur, GstSeekType stop_type, gint64 stop ); -static int __gst_pending_seek ( mm_player_t* player ); - -static int __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called); -static int __gst_get_position(mm_player_t* player, int format, unsigned long *position); -static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos); -static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position); -static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param); - -static gint __gst_handle_core_error( mm_player_t* player, int code ); -static gint __gst_handle_library_error( mm_player_t* player, int code ); -static gint __gst_handle_resource_error( mm_player_t* player, int code ); -static gint __gst_handle_stream_error( mm_player_t* player, GError* error, GstMessage * message ); -static gint __gst_transform_gsterror( mm_player_t* player, GstMessage * message, GError* error); -static gboolean __gst_send_event_to_sink( mm_player_t* player, GstEvent* event ); - -static int __mmplayer_set_pcm_extraction(mm_player_t* player); -static gboolean __mmplayer_can_extract_pcm( mm_player_t* player ); - -/*fadeout */ -static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time); -static void __mmplayer_undo_sound_fadedown(mm_player_t* player); - -static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data); -static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps); - -/* util */ -const gchar * __get_state_name ( int state ); -static gboolean __is_streaming( mm_player_t* player ); -static gboolean __is_rtsp_streaming( mm_player_t* player ); -static gboolean __is_wfd_streaming( mm_player_t* player ); -static gboolean __is_live_streaming ( mm_player_t* player ); -static gboolean __is_http_streaming( mm_player_t* player ); -static gboolean __is_http_live_streaming( mm_player_t* player ); -static gboolean __is_dash_streaming( mm_player_t* player ); -static gboolean __is_smooth_streaming( mm_player_t* player ); -static gboolean __is_http_progressive_down(mm_player_t* player); -static gboolean __is_es_buff_src(mm_player_t* player); -static gboolean __has_suffix(mm_player_t * player, const gchar * suffix); - -static int __mmplayer_realize_streaming_ext(mm_player_t* player); -static int __mmplayer_unrealize_streaming_ext(mm_player_t *player); -static int __mmplayer_start_streaming_ext(mm_player_t *player); -static int __mmplayer_destroy_streaming_ext(mm_player_t* player); -static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay); - -static gboolean __mmplayer_verify_next_play_path(mm_player_t *player); -static void __mmplayer_activate_next_source(mm_player_t *player, GstState target); -static void __mmplayer_check_pipeline(mm_player_t* player); -static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type); -static void __mmplayer_deactivate_old_path(mm_player_t *player); -#if 0 // We'll need this in future. -static int __mmplayer_gst_switching_element(mm_player_t *player, GstElement *search_from, const gchar *removal_name, const gchar *new_element_name); -#endif - -static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg); -static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name); -static gboolean __mmplayer_can_do_interrupt(mm_player_t *player); - -/* device change post proc */ -void __mmplayer_device_change_post_process(gpointer user); -void __mmplayer_set_required_cb_score(mm_player_t* player, guint score); -void __mmplayer_inc_cb_score(mm_player_t* player); -void __mmplayer_post_proc_reset(mm_player_t* player); -void __mmplayer_device_change_trigger_post_process(mm_player_t* player); -static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player); -static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name); -static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data); -static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data); -static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data); -static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data); -static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data); -static gboolean __gst_seek_audio_data (GstElement * appsrc, guint64 position, gpointer user_data); -static gboolean __gst_seek_video_data (GstElement * appsrc, guint64 position, gpointer user_data); -static gboolean __gst_seek_subtitle_data (GstElement * appsrc, guint64 position, gpointer user_data); -/*=========================================================================================== -| | -| FUNCTION DEFINITIONS | -| | -========================================================================================== */ - -#if 0 //debug -static void -print_tag (const GstTagList * list, const gchar * tag, gpointer unused) -{ - gint i, count; - - count = gst_tag_list_get_tag_size (list, tag); - - debug_log("count = %d", count); - - for (i = 0; i < count; i++) { - gchar *str; - - if (gst_tag_get_type (tag) == G_TYPE_STRING) { - if (!gst_tag_list_get_string_index (list, tag, i, &str)) - g_assert_not_reached (); - } else { - str = - g_strdup_value_contents (gst_tag_list_get_value_index (list, tag, i)); - } - - if (i == 0) { - g_print (" %15s: %s\n", gst_tag_get_nick (tag), str); - } else { - g_print (" : %s\n", str); - } - - g_free (str); - } -} -#endif - -/* implementing player FSM */ -/* FIXIT : We need to handle state transition also at here since start api is no more sync */ -int -__mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command) -{ - MMPlayerStateType current_state = MM_PLAYER_STATE_NUM; - MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM; -// MMPlayerStateType target_state = MM_PLAYER_STATE_NUM; -// MMPlayerStateType prev_state = MM_PLAYER_STATE_NUM; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - //debug_log("incomming command : %d \n", command ); - - current_state = MMPLAYER_CURRENT_STATE(player); - pending_state = MMPLAYER_PENDING_STATE(player); -// target_state = MMPLAYER_TARGET_STATE(player); -// prev_state = MMPLAYER_PREV_STATE(player); - - MMPLAYER_PRINT_STATE(player); - - switch( command ) - { - case MMPLAYER_COMMAND_CREATE: - { - MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL; - - if ( current_state == MM_PLAYER_STATE_NULL || - current_state == MM_PLAYER_STATE_READY || - current_state == MM_PLAYER_STATE_PAUSED || - current_state == MM_PLAYER_STATE_PLAYING ) - goto NO_OP; - } - break; - - case MMPLAYER_COMMAND_DESTROY: - { - /* destroy can called anytime */ - - MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE; - } - break; - - case MMPLAYER_COMMAND_REALIZE: - { - MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY; - - if ( pending_state != MM_PLAYER_STATE_NONE ) - { - goto INVALID_STATE; - } - else - { - /* need ready state to realize */ - if ( current_state == MM_PLAYER_STATE_READY ) - goto NO_OP; - - if ( current_state != MM_PLAYER_STATE_NULL ) - goto INVALID_STATE; - } - } - break; - - case MMPLAYER_COMMAND_UNREALIZE: - { - MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL; - - if ( current_state == MM_PLAYER_STATE_NULL ) - goto NO_OP; - } - break; - - case MMPLAYER_COMMAND_START: - { - MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING; - - if ( pending_state == MM_PLAYER_STATE_NONE ) - { - if ( current_state == MM_PLAYER_STATE_PLAYING ) - goto NO_OP; - else if ( current_state != MM_PLAYER_STATE_READY && - current_state != MM_PLAYER_STATE_PAUSED ) - goto INVALID_STATE; - } - else if ( pending_state == MM_PLAYER_STATE_PLAYING ) - { - goto ALREADY_GOING; - } - else if ( pending_state == MM_PLAYER_STATE_PAUSED ) - { - debug_log("player is going to paused state, just change the pending state as playing"); - } - else - { - goto INVALID_STATE; - } - } - break; - - case MMPLAYER_COMMAND_STOP: - { - MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY; - - if ( current_state == MM_PLAYER_STATE_READY ) - goto NO_OP; - - /* need playing/paused state to stop */ - if ( current_state != MM_PLAYER_STATE_PLAYING && - current_state != MM_PLAYER_STATE_PAUSED ) - goto INVALID_STATE; - } - break; - - case MMPLAYER_COMMAND_PAUSE: - { - if ( MMPLAYER_IS_LIVE_STREAMING( player ) ) - goto NO_OP; - - if (player->doing_seek) - goto NOT_COMPLETED_SEEK; - - MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED; - - if ( pending_state == MM_PLAYER_STATE_NONE ) - { - if ( current_state == MM_PLAYER_STATE_PAUSED ) - goto NO_OP; - else if ( current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY ) // support loading state of broswer - goto INVALID_STATE; - } - else if ( pending_state == MM_PLAYER_STATE_PAUSED ) - { - goto ALREADY_GOING; - } - else if ( pending_state == MM_PLAYER_STATE_PLAYING ) - { - if ( current_state == MM_PLAYER_STATE_PAUSED ) { - debug_log("player is PAUSED going to PLAYING, just change the pending state as PAUSED"); - } else { - goto INVALID_STATE; - } - } - } - break; - - case MMPLAYER_COMMAND_RESUME: - { - - if (player->doing_seek) - goto NOT_COMPLETED_SEEK; - - MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING; - - if ( pending_state == MM_PLAYER_STATE_NONE ) - { - if ( current_state == MM_PLAYER_STATE_PLAYING ) - goto NO_OP; - else if ( current_state != MM_PLAYER_STATE_PAUSED ) - goto INVALID_STATE; - } - else if ( pending_state == MM_PLAYER_STATE_PLAYING ) - { - goto ALREADY_GOING; - } - else if ( pending_state == MM_PLAYER_STATE_PAUSED ) - { - debug_log("player is going to paused state, just change the pending state as playing"); - } - else - { - goto INVALID_STATE; - } - } - break; - - default: - break; - } - player->cmd = command; - - return MM_ERROR_NONE; - -INVALID_STATE: - debug_warning("since player is in wrong state(%s). it's not able to apply the command(%d)", - MMPLAYER_STATE_GET_NAME(current_state), command); - return MM_ERROR_PLAYER_INVALID_STATE; - -NOT_COMPLETED_SEEK: - debug_warning("not completed seek"); - return MM_ERROR_PLAYER_DOING_SEEK; - -NO_OP: - debug_warning("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state)); - return MM_ERROR_PLAYER_NO_OP; - -ALREADY_GOING: - debug_warning("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state)); - return MM_ERROR_PLAYER_NO_OP; -} - -int -__mmplayer_gst_set_state (mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout) // @ -{ - GstState element_state = GST_STATE_VOID_PENDING; - GstState element_pending_state = GST_STATE_VOID_PENDING; - GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - return_val_if_fail ( element, MM_ERROR_INVALID_ARGUMENT ); - - debug_log("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state)); - - /* set state */ - ret = gst_element_set_state(element, state); - - if ( ret == GST_STATE_CHANGE_FAILURE ) - { - debug_error("failed to set [%s] state\n", GST_ELEMENT_NAME(element)); - - /* dump state of all element */ - __mmplayer_dump_pipeline_state( player ); - - return MM_ERROR_PLAYER_INTERNAL; - } - - /* return here so state transition to be done in async mode */ - if ( async ) - { - debug_log("async state transition. not waiting for state complete.\n"); - return MM_ERROR_NONE; - } - - /* wait for state transition */ - ret = gst_element_get_state( element, &element_state, &element_pending_state, timeout * GST_SECOND ); - - if ( ret == GST_STATE_CHANGE_FAILURE || ( state != element_state ) ) - { - debug_error("failed to change [%s] element state to [%s] within %d sec\n", - GST_ELEMENT_NAME(element), - gst_element_state_get_name(state), timeout ); - - debug_error(" [%s] state : %s pending : %s \n", - GST_ELEMENT_NAME(element), - gst_element_state_get_name(element_state), - gst_element_state_get_name(element_pending_state) ); - - /* dump state of all element */ - __mmplayer_dump_pipeline_state( player ); - - return MM_ERROR_PLAYER_INTERNAL; - } - - debug_log("[%s] element state has changed\n", GST_ELEMENT_NAME(element)); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -static void -__mmplayer_videostream_cb(GstElement *element, void *data, -int width, int height, gpointer user_data) // @ -{ - mm_player_t* player = (mm_player_t*)user_data; - - return_if_fail ( player ); - - MMPLAYER_FENTER(); - - if (player->is_drm_file) - { - MMMessageParamType msg_param = { 0, }; - debug_warning("not supported in drm file"); - msg_param.code = MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION; - MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param ); - } - else if ( !player->set_mode.media_packet_video_stream && player->video_stream_cb) - { - MMPlayerVideoStreamDataType stream; - - /* clear stream data structure */ - memset(&stream, 0x0, sizeof(MMPlayerVideoStreamDataType)); - - stream.data[0] = data; - stream.length_total = width * height * 4; // for rgb 32bit - stream.height = height; - stream.width = width; - player->video_stream_cb(&stream, player->video_stream_cb_user_param); - } - - MMPLAYER_FLEAVE(); -} - -static void -__mmplayer_videoframe_render_error_cb(GstElement *element, void *error_id, gpointer data) -{ - mm_player_t* player = (mm_player_t*)data; - - return_if_fail ( player ); - - MMPLAYER_FENTER(); - - if (player->video_frame_render_error_cb ) - { - if (player->attrs) - { - int surface_type = 0; - mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type); - switch (surface_type) - { - case MM_DISPLAY_SURFACE_X_EXT: - player->video_frame_render_error_cb((unsigned int*)error_id, player->video_frame_render_error_cb_user_param); - debug_log("display surface type(X_EXT) : render error callback(%p) is finished", player->video_frame_render_error_cb); - break; - default: - debug_error("video_frame_render_error_cb was set, but this surface type(%d) is not supported", surface_type); - break; - } - } - else - { - debug_error("could not get surface type"); - } - } - else - { - debug_warning("video_frame_render_error_cb was not set"); - } - - MMPLAYER_FLEAVE(); -} - -void -__mmplayer_device_change_post_process(gpointer user) -{ - mm_player_t* player = (mm_player_t*)user; - unsigned long position = 0; - MMPlayerStateType current_state = MM_PLAYER_STATE_NONE; - MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE; - - MMPLAYER_FENTER(); - - if (! player || - ! player->pipeline || - ! player->pipeline->mainbin || - ! player->pipeline->mainbin[MMPLAYER_M_PIPE].gst ) - { - goto EXIT; - } - - current_state = MMPLAYER_CURRENT_STATE(player); - pending_state = MMPLAYER_PENDING_STATE(player); - - if (player->post_proc.need_pause_and_resume) - { - debug_log("pausing"); - if ((pending_state == MM_PLAYER_STATE_PLAYING) || - ((pending_state == MM_PLAYER_STATE_NONE) && (current_state != MM_PLAYER_STATE_PAUSED))) - gst_element_set_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED); - } - - /* seek should be done within pause and resume */ - if (player->post_proc.need_seek) - { - debug_log("seeking"); - __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position); - debug_log(">> seek to current position = %ld ms", position); - __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE); - } - - if (player->post_proc.need_pause_and_resume) - { - debug_log("resuming"); - if ((pending_state == MM_PLAYER_STATE_PLAYING) || - ((pending_state == MM_PLAYER_STATE_NONE) && (current_state != MM_PLAYER_STATE_PAUSED))) - gst_element_set_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING); - } - - /* async */ - if (player->post_proc.need_async) - { - debug_log("setting async"); - - /* TODO : need some comment here */ - if (player->pipeline->textbin && player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst) - g_object_set (G_OBJECT (player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL); - } - -EXIT: - /* reset all */ - __mmplayer_post_proc_reset(player); - return; -} - -void __mmplayer_set_required_cb_score(mm_player_t* player, guint score) -{ - return_if_fail(player); - player->post_proc.required_cb_score = score; - debug_log("set required score to : %d", score); -} - -void __mmplayer_inc_cb_score(mm_player_t* player) -{ - return_if_fail(player); - player->post_proc.cb_score++; - debug_log("post proc cb score increased to %d", player->post_proc.cb_score); -} - -void __mmplayer_post_proc_reset(mm_player_t* player) -{ - return_if_fail(player); - - /* check if already triggered */ - if (player->post_proc.id) - { - /* TODO : need to consider multiple main context. !!!! */ - if (FALSE == g_source_remove(player->post_proc.id) ) - { - debug_error("failed to remove exist post_proc item"); - } - player->post_proc.id = 0; - } - - memset(&player->post_proc, 0, sizeof(mm_player_post_proc_t)); - - /* set default required cb score 1 as only audio device has changed in this case. - if display status is changed with audio device, required cb score is set 2 in display status callback. - this logic bases on the assumption which audio device callback is called after calling display status callback. */ - player->post_proc.required_cb_score = 1; -} - -void -__mmplayer_device_change_trigger_post_process(mm_player_t* player) -{ - return_if_fail(player); - - /* check score */ - if ( player->post_proc.cb_score < player->post_proc.required_cb_score ) - { - /* wait for next turn */ - debug_log("wait for next turn. required cb score : %d current score : %d\n", - player->post_proc.required_cb_score, player->post_proc.cb_score); - return; - } - - /* check if already triggered */ - if (player->post_proc.id) - { - /* TODO : need to consider multiple main context. !!!! */ - if (FALSE == g_source_remove(player->post_proc.id) ) - { - debug_error("failed to remove exist post_proc item"); - } - player->post_proc.id = 0; - } - - player->post_proc.id = g_idle_add((GSourceFunc)__mmplayer_device_change_post_process, (gpointer)player); -} -#if 0 -/* NOTE : Sound module has different latency according to output device So, - * synchronization problem can be happened whenever device is changed. - * To avoid this issue, we do reset avsystem or seek as workaroud. - */ -static void -__mmplayer_sound_device_info_changed_cb_func (MMSoundDevice_t device_h, int changed_info_type, void *user_data) -{ - int ret; - mm_sound_device_type_e device_type; - mm_player_t* player = (mm_player_t*) user_data; - - return_if_fail( player ); - - debug_warning("device_info_changed_cb is called, device_h[0x%x], changed_info_type[%d]\n", device_h, changed_info_type); - - __mmplayer_inc_cb_score(player); - - /* get device type with device_h*/ - ret = mm_sound_get_device_type(device_h, &device_type); - if (ret) { - debug_error("failed to mm_sound_get_device_type()\n"); - } - - /* do pause and resume only if video is playing */ - if ( player->videodec_linked && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING ) - { - switch (device_type) - { - case MM_SOUND_DEVICE_TYPE_BLUETOOTH: - case MM_SOUND_DEVICE_TYPE_AUDIOJACK: - case MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER: - case MM_SOUND_DEVICE_TYPE_HDMI: - case MM_SOUND_DEVICE_TYPE_MIRRORING: - { - player->post_proc.need_pause_and_resume = TRUE; - } - break; - - default: - debug_log("do nothing"); - } - } - debug_warning("dispatched"); - - __mmplayer_device_change_trigger_post_process(player); -} -#endif -/* This function should be called after the pipeline goes PAUSED or higher -state. */ -gboolean -_mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag) // @ -{ - static gboolean has_duration = FALSE; - static gboolean has_video_attrs = FALSE; - static gboolean has_audio_attrs = FALSE; - static gboolean has_bitrate = FALSE; - gboolean missing_only = FALSE; - gboolean all = FALSE; - gint64 dur_nsec = 0; - GstStructure* p = NULL; - MMHandleType attrs = 0; - gchar *path = NULL; - gint stream_service_type = STREAMING_SERVICE_NONE; - struct stat sb; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, FALSE ); - - /* check player state here */ - if ( MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED && - MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING ) - { - /* give warning now only */ - debug_warning("be careful. content attributes may not available in this state "); - } - - /* get content attribute first */ - attrs = MMPLAYER_GET_ATTRS(player); - if ( !attrs ) - { - debug_error("cannot get content attribute"); - return FALSE; - } - - /* get update flag */ - - if ( flag & ATTR_MISSING_ONLY ) - { - missing_only = TRUE; - debug_log("updating missed attr only"); - } - - if ( flag & ATTR_ALL ) - { - all = TRUE; - has_duration = FALSE; - has_video_attrs = FALSE; - has_audio_attrs = FALSE; - has_bitrate = FALSE; - - debug_log("updating all attrs"); - } - - if ( missing_only && all ) - { - debug_warning("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!"); - missing_only = FALSE; - } - - if ( (flag & ATTR_DURATION) || (!has_duration && missing_only) || all ) - { - debug_log("try to update duration"); - has_duration = FALSE; - - if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec )) - { - player->duration = dur_nsec; - debug_warning("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec)); - } - - /* try to get streaming service type */ - stream_service_type = __mmplayer_get_stream_service_type( player ); - mm_attrs_set_int_by_name ( attrs, "streaming_type", stream_service_type ); - - /* check duration is OK */ - if ( dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING( player ) ) - { - /* FIXIT : find another way to get duration here. */ - debug_error("finally it's failed to get duration from pipeline. progressbar will not work correctely!"); - } - else - { - /*update duration */ - mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec)); - has_duration = TRUE; - } - } - - if ( (flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all ) - { - /* update audio params - NOTE : We need original audio params and it can be only obtained from src pad of audio - decoder. Below code only valid when we are not using 'resampler' just before - 'audioconverter'. */ - - debug_log("try to update audio attrs"); - has_audio_attrs = FALSE; - - if ( player->pipeline->audiobin && - player->pipeline->audiobin[MMPLAYER_A_SINK].gst ) - { - GstCaps *caps_a = NULL; - GstPad* pad = NULL; - gint samplerate = 0, channels = 0; - - pad = gst_element_get_static_pad( - player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink" ); - - if ( pad ) - { - caps_a = gst_pad_get_current_caps( pad ); - - if ( caps_a ) - { - p = gst_caps_get_structure (caps_a, 0); - - mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate); - - gst_structure_get_int (p, "rate", &samplerate); - mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate); - - gst_structure_get_int (p, "channels", &channels); - mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels); - - secure_debug_log("samplerate : %d channels : %d", samplerate, channels); - - gst_caps_unref( caps_a ); - caps_a = NULL; - - has_audio_attrs = TRUE; - } - else - { - debug_warning("not ready to get audio caps"); - } - - gst_object_unref( pad ); - } - else - { - debug_warning("failed to get pad from audiosink"); - } - } - } - - if ( (flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all ) - { - debug_log("try to update video attrs"); - has_video_attrs = FALSE; - - if ( player->pipeline->videobin && - player->pipeline->videobin[MMPLAYER_V_SINK].gst ) - { - GstCaps *caps_v = NULL; - GstPad* pad = NULL; - gint tmpNu, tmpDe; - gint width, height; - - pad = gst_element_get_static_pad( player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink" ); - if ( pad ) - { - caps_v = gst_pad_get_current_caps( pad ); - - /* Use v_stream_caps, if fail to get video_sink sink pad*/ - if (!caps_v && player->v_stream_caps) - { - caps_v = player->v_stream_caps; - gst_caps_ref(caps_v); - } - - if (caps_v) - { - p = gst_caps_get_structure (caps_v, 0); - gst_structure_get_int (p, "width", &width); - mm_attrs_set_int_by_name(attrs, "content_video_width", width); - - gst_structure_get_int (p, "height", &height); - mm_attrs_set_int_by_name(attrs, "content_video_height", height); - - gst_structure_get_fraction (p, "framerate", &tmpNu, &tmpDe); - - secure_debug_log("width : %d height : %d", width, height ); - - gst_caps_unref( caps_v ); - caps_v = NULL; - - if (tmpDe > 0) - { - mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe); - secure_debug_log("fps : %d", tmpNu / tmpDe); - } - - has_video_attrs = TRUE; - } - else - { - debug_log("no negitiated caps from videosink"); - } - gst_object_unref( pad ); - pad = NULL; - } - else - { - debug_log("no videosink sink pad"); - } - } - } - - - if ( (flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all ) - { - has_bitrate = FALSE; - - /* FIXIT : please make it clear the dependancy with duration/codec/uritype */ - if (player->duration) - { - guint64 data_size = 0; - - if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) - { - mm_attrs_get_string_by_name(attrs, "profile_uri", &path); - - if (stat(path, &sb) == 0) - { - data_size = (guint64)sb.st_size; - } - } - else if (MMPLAYER_IS_HTTP_STREAMING(player)) - { - data_size = player->http_content_size; - } - debug_log("try to update bitrate : data_size = %lld", data_size); - - if (data_size) - { - guint64 bitrate = 0; - guint64 msec_dur = 0; - - msec_dur = GST_TIME_AS_MSECONDS(player->duration); - bitrate = data_size * 8 * 1000 / msec_dur; - secure_debug_log("file size : %u, video bitrate = %llu", data_size, bitrate); - mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate); - - has_bitrate = TRUE; - } - - if (MMPLAYER_IS_RTSP_STREAMING(player)) - { - if(player->total_bitrate) - { - mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate); - has_bitrate = TRUE; - } - } - } - } - - /* validate all */ - if ( mmf_attrs_commit ( attrs ) ) - { - debug_error("failed to update attributes\n"); - return FALSE; - } - - MMPLAYER_FLEAVE(); - - return TRUE; -} - -gint __mmplayer_get_stream_service_type( mm_player_t* player ) -{ - gint streaming_type = STREAMING_SERVICE_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player && - player->pipeline && - player->pipeline->mainbin && - player->pipeline->mainbin[MMPLAYER_M_SRC].gst, - FALSE ); - - /* streaming service type if streaming */ - if ( ! MMPLAYER_IS_STREAMING(player) ) - return STREAMING_SERVICE_NONE; - - if (MMPLAYER_IS_HTTP_STREAMING(player)) - { - streaming_type = (player->duration == 0) ? - STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD; - } - - switch ( streaming_type ) - { - case STREAMING_SERVICE_LIVE: - debug_log("it's live streaming"); - break; - case STREAMING_SERVICE_VOD: - debug_log("it's vod streaming"); - break; - case STREAMING_SERVICE_NONE: - debug_error("should not get here"); - break; - default: - debug_error("should not get here"); - } - - player->streaming_type = streaming_type; - MMPLAYER_FLEAVE(); - - return streaming_type; -} - - -/* this function sets the player state and also report - * it to applicaton by calling callback function - */ -int -__mmplayer_set_state(mm_player_t* player, int state) // @ -{ - MMMessageParamType msg = {0, }; - int sound_result = MM_ERROR_NONE; - gboolean post_bos = FALSE; - gboolean interrupted_by_asm = FALSE; - int ret = MM_ERROR_NONE; - - return_val_if_fail ( player, FALSE ); - - if ( MMPLAYER_CURRENT_STATE(player) == state ) - { - debug_warning("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state)); - MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE; - return ret; - } - - /* update player states */ - MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player); - MMPLAYER_CURRENT_STATE(player) = state; - - /* FIXIT : it's better to do like below code - if ( MMPLAYER_CURRENT_STATE(player) == MMPLAYER_TARGET_STATE(player) ) - MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE; - and add more code to handling PENDING_STATE. - */ - if ( MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player) ) - MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE; - - /* print state */ - MMPLAYER_PRINT_STATE(player); - - /* do some FSM stuffs before posting new state to application */ - interrupted_by_asm = player->sound_focus.by_asm_cb; - - switch ( MMPLAYER_CURRENT_STATE(player) ) - { - case MM_PLAYER_STATE_NULL: - case MM_PLAYER_STATE_READY: - { - if (player->cmd == MMPLAYER_COMMAND_STOP) - { - sound_result = _mmplayer_sound_release_focus(&player->sound_focus); - if ( sound_result != MM_ERROR_NONE ) - { - debug_error("failed to release sound focus\n"); - return MM_ERROR_POLICY_INTERNAL; - } - } - } - break; - - case MM_PLAYER_STATE_PAUSED: - { - if ( ! player->sent_bos ) - { - int found = 0; - #define MMPLAYER_MAX_SOUND_PRIORITY 3 - - /* it's first time to update all content attrs. */ - _mmplayer_update_content_attrs( player, ATTR_ALL ); - /* set max sound priority to keep own sound and not to mute other's one */ - mm_attrs_get_int_by_name(player->attrs, "content_video_found", &found); - if (found) - { - mm_attrs_get_int_by_name(player->attrs, "content_audio_found", &found); - if (found) - { - debug_log("set max audio priority"); - g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "priority", MMPLAYER_MAX_SOUND_PRIORITY, NULL); - } - } - - } - - /* add audio callback probe if condition is satisfied */ - if ( ! player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex) - { - __mmplayer_configure_audio_callback(player); - /* FIXIT : handle return value */ - } - - if (!MMPLAYER_IS_STREAMING(player) || (player->streamer && !player->streamer->is_buffering)) - { - sound_result = _mmplayer_sound_release_focus(&player->sound_focus); - if ( sound_result != MM_ERROR_NONE ) - { - debug_error("failed to release sound focus\n"); - return MM_ERROR_POLICY_INTERNAL; - } - } - } - break; - - case MM_PLAYER_STATE_PLAYING: - { - /* try to get content metadata */ - if ( ! player->sent_bos ) - { - /* NOTE : giving ATTR_MISSING_ONLY may have dependency with - * c-api since c-api doesn't use _start() anymore. It may not work propery with - * legacy mmfw-player api */ - _mmplayer_update_content_attrs( player, ATTR_MISSING_ONLY); - } - - if ( (player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME) ) - { - if (!player->sent_bos) - { - __mmplayer_handle_missed_plugin ( player ); - } - sound_result = _mmplayer_sound_acquire_focus(&player->sound_focus); - if (sound_result != MM_ERROR_NONE) - { - // FIXME : need to check history - if (player->pipeline->videobin) - { - MMMessageParamType msg = {0, }; - - debug_error("failed to go ahead because of video conflict\n"); - - msg.union_type = MM_MSG_UNION_CODE; - msg.code = MM_ERROR_POLICY_INTERRUPTED; - MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg); - - _mmplayer_unrealize((MMHandleType)player); - } - else - { - debug_error("failed to play by sound focus error : 0x%X\n", sound_result); - _mmplayer_pause((MMHandleType)player); - return sound_result; - } - - return MM_ERROR_POLICY_INTERNAL; - } - } - - if ( player->resumed_by_rewind && player->playback_rate < 0.0 ) - { - /* initialize because auto resume is done well. */ - player->resumed_by_rewind = FALSE; - player->playback_rate = 1.0; - } - - if ( !player->sent_bos ) - { - /* check audio codec field is set or not - * we can get it from typefinder or codec's caps. - */ - gchar *audio_codec = NULL; - mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec); - - /* The codec format can't be sent for audio only case like amr, mid etc. - * Because, parser don't make related TAG. - * So, if it's not set yet, fill it with found data. - */ - if ( ! audio_codec ) - { - if ( g_strrstr(player->type, "audio/midi")) - { - audio_codec = g_strdup("MIDI"); - - } - else if ( g_strrstr(player->type, "audio/x-amr")) - { - audio_codec = g_strdup("AMR"); - } - else if ( g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion=(int)1")) - { - audio_codec = g_strdup("AAC"); - } - else - { - audio_codec = g_strdup("unknown"); - } - mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec); - - MMPLAYER_FREEIF(audio_codec); - mmf_attrs_commit(player->attrs); - debug_log("set audio codec type with caps\n"); - } - - post_bos = TRUE; - } - } - break; - - case MM_PLAYER_STATE_NONE: - default: - debug_warning("invalid target state, there is nothing to do.\n"); - break; - } - - - /* post message to application */ - if (MMPLAYER_TARGET_STATE(player) == state) - { - /* fill the message with state of player */ - msg.state.previous = MMPLAYER_PREV_STATE(player); - msg.state.current = MMPLAYER_CURRENT_STATE(player); - - debug_log ("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player))); - - /* state changed by asm callback */ - if ( interrupted_by_asm ) - { - msg.union_type = MM_MSG_UNION_CODE; - msg.code = player->sound_focus.focus_changed_msg; /* FIXME: player.c convert function have to be modified. */ - MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg ); - } - /* state changed by usecase */ - else - { - MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_CHANGED, &msg ); - } - } - else - { - debug_log ("intermediate state, do nothing.\n"); - MMPLAYER_PRINT_STATE(player); - return ret; - } - - if ( post_bos ) - { - MMPLAYER_POST_MSG ( player, MM_MESSAGE_BEGIN_OF_STREAM, NULL ); - player->sent_bos = TRUE; - } - - return ret; -} - -gboolean -__mmplayer_post_message(mm_player_t* player, enum MMMessageType msgtype, MMMessageParamType* param) // @ -{ - return_val_if_fail( player, FALSE ); - - if ( !player->msg_cb ) - { - return FALSE; - } - - //debug_log("Message (type : %d) will be posted using msg-cb(%p). \n", msgtype, player->msg_cb); - - player->msg_cb(msgtype, param, player->msg_cb_param); - - return TRUE; -} - -static gpointer __mmplayer_next_play_thread(gpointer data) -{ - mm_player_t* player = (mm_player_t*) data; - MMPlayerGstElement *mainbin = NULL; - - return_val_if_fail ( player, NULL ); - - g_mutex_lock(&player->next_play_thread_mutex); - while ( ! player->next_play_thread_exit ) - { - debug_log("next play thread started. waiting for signal.\n"); - g_cond_wait(&player->next_play_thread_cond, &player->next_play_thread_mutex ); - - debug_log("reconfigure pipeline for gapless play.\n"); - - if ( player->next_play_thread_exit ) - { - if(player->gapless.reconfigure) - { - player->gapless.reconfigure = false; - MMPLAYER_PLAYBACK_UNLOCK(player); - } - debug_log("exiting gapless play thread\n"); - break; - } - - mainbin = player->pipeline->mainbin; - - MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER); - MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX); - MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG); - MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND); - MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC); - - __mmplayer_activate_next_source(player, GST_STATE_PLAYING); - } - g_mutex_unlock(&player->next_play_thread_mutex); - - return NULL; -} - -static gpointer __mmplayer_repeat_thread(gpointer data) -{ - mm_player_t* player = (mm_player_t*) data; - gboolean ret_value = FALSE; - MMHandleType attrs = 0; - gint count = 0; - - return_val_if_fail ( player, NULL ); - - g_mutex_lock(&player->repeat_thread_mutex); - while ( ! player->repeat_thread_exit ) - { - debug_log("repeat thread started. waiting for signal.\n"); - g_cond_wait(&player->repeat_thread_cond, &player->repeat_thread_mutex ); - - if ( player->repeat_thread_exit ) - { - debug_log("exiting repeat thread\n"); - break; - } - - - /* lock */ - g_mutex_lock(&player->cmd_lock); - - attrs = MMPLAYER_GET_ATTRS(player); - - if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE) - { - debug_error("can not get play count\n"); - break; - } - - if ( player->section_repeat ) - { - ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end); - } - else - { - if ( player->playback_rate < 0.0 ) - { - player->resumed_by_rewind = TRUE; - _mmplayer_set_mute((MMHandleType)player, 0); - MMPLAYER_POST_MSG( player, MM_MESSAGE_RESUMED_BY_REW, NULL ); - } - - ret_value = __gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate, - GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, - 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); - - /* initialize */ - player->sent_bos = FALSE; - } - - if ( ! ret_value ) - { - debug_error("failed to set position to zero for rewind\n"); - continue; - } - - /* decrease play count */ - if ( count > 1 ) - { - /* we successeded to rewind. update play count and then wait for next EOS */ - count--; - - mm_attrs_set_int_by_name(attrs, "profile_play_count", count); - - /* commit attribute */ - if ( mmf_attrs_commit ( attrs ) ) - { - debug_error("failed to commit attribute\n"); - } - } - - /* unlock */ - g_mutex_unlock(&player->cmd_lock); - } - - g_mutex_unlock(&player->repeat_thread_mutex); - return NULL; -} - -static void -__mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg) -{ - MMHandleType attrs = 0; - guint64 data_size = 0; - gchar* path = NULL; - unsigned long pos_msec = 0; - struct stat sb; - - return_if_fail( player && player->pipeline && player->pipeline->mainbin); - - __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec); // update last_position - - attrs = MMPLAYER_GET_ATTRS(player); - if ( !attrs ) - { - debug_error("fail to get attributes.\n"); - return; - } - - if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) - { - mm_attrs_get_string_by_name(attrs, "profile_uri", &path); - - if (stat(path, &sb) == 0) - { - data_size = (guint64)sb.st_size; - } - } - else if (MMPLAYER_IS_HTTP_STREAMING(player)) - { - data_size = player->http_content_size; - } - - __mm_player_streaming_buffering( player->streamer, - buffering_msg, - data_size, - player->last_position, - player->duration); - - __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst); - - return; -} - - -static void -__mmplayer_handle_buffering_message ( mm_player_t* player ) -{ - MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE; - MMPlayerStateType current_state = MM_PLAYER_STATE_NONE; - MMPlayerStateType target_state = MM_PLAYER_STATE_NONE; - MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE; - - return_if_fail ( player ); - - prev_state = MMPLAYER_PREV_STATE(player); - current_state = MMPLAYER_CURRENT_STATE(player); - target_state = MMPLAYER_TARGET_STATE(player); - pending_state = MMPLAYER_PENDING_STATE(player); - - if (MMPLAYER_IS_LIVE_STREAMING(player)) - return; - - if ( !player->streamer->is_buffering ) - { - debug_log( "player state : prev %s, current %s, pending %s, target %s \n", - MMPLAYER_STATE_GET_NAME(prev_state), - MMPLAYER_STATE_GET_NAME(current_state), - MMPLAYER_STATE_GET_NAME(pending_state), - MMPLAYER_STATE_GET_NAME(target_state)); - - /* NOTE : if buffering has done, player has to go to target state. */ - switch ( target_state ) - { - case MM_PLAYER_STATE_PAUSED : - { - switch ( pending_state ) - { - case MM_PLAYER_STATE_PLAYING: - { - __gst_pause ( player, TRUE ); - } - break; - - case MM_PLAYER_STATE_PAUSED: - { - debug_log("player is already going to paused state, there is nothing to do.\n"); - } - break; - - case MM_PLAYER_STATE_NONE: - case MM_PLAYER_STATE_NULL: - case MM_PLAYER_STATE_READY: - default : - { - debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) ); - } - break; - } - } - break; - - case MM_PLAYER_STATE_PLAYING : - { - switch ( pending_state ) - { - case MM_PLAYER_STATE_NONE: - { - if (current_state != MM_PLAYER_STATE_PLAYING) - __gst_resume ( player, TRUE ); - } - break; - - case MM_PLAYER_STATE_PAUSED: - { - /* NOTE: It should be worked as asynchronously. - * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly. - */ - __gst_resume ( player, TRUE ); - } - break; - - case MM_PLAYER_STATE_PLAYING: - { - debug_log("player is already going to playing state, there is nothing to do.\n"); - } - break; - - case MM_PLAYER_STATE_NULL: - case MM_PLAYER_STATE_READY: - default : - { - debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) ); - } - break; - } - } - break; - - case MM_PLAYER_STATE_NULL : - case MM_PLAYER_STATE_READY : - case MM_PLAYER_STATE_NONE : - default: - { - debug_warning("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state) ); - } - break; - } - } - else - { - /* NOTE : during the buffering, pause the player for stopping pipeline clock. - * it's for stopping the pipeline clock to prevent dropping the data in sink element. - */ - switch ( pending_state ) - { - case MM_PLAYER_STATE_NONE: - { - if (current_state != MM_PLAYER_STATE_PAUSED) - { - debug_log("set pause state during buffering\n"); - __gst_pause ( player, TRUE ); - - // to cover the weak-signal environment. - if (MMPLAYER_IS_RTSP_STREAMING(player)) - { - unsigned long position = 0; - gint64 pos_msec = 0; - - debug_log("[RTSP] seek to the buffering start point\n"); - - if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position )) - { - debug_error("failed to get position\n"); - break; - } - - /* key unit seek */ - pos_msec = position * G_GINT64_CONSTANT(1000000); - - __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0, - GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, - pos_msec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); - } - } - } - break; - - case MM_PLAYER_STATE_PLAYING: - { - __gst_pause ( player, TRUE ); - } - break; - - case MM_PLAYER_STATE_PAUSED: - { - } - break; - - case MM_PLAYER_STATE_NULL: - case MM_PLAYER_STATE_READY: - default : - { - debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) ); - } - break; - } - } -} - -static void -__mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop) -{ - MMPlayerGstElement *textbin; - MMPLAYER_FENTER(); - - return_if_fail ( player && - player->pipeline && - player->pipeline->textbin); - - return_if_fail (player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst); - - textbin = player->pipeline->textbin; - - if (is_drop) - { - debug_log("Drop subtitle text after getting EOS\n"); - - g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL); - g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL); - - player->is_subtitle_force_drop = TRUE; - } - else - { - if (player->is_subtitle_force_drop == TRUE) - { - debug_log("Enable subtitle data path without drop\n"); - - g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL); - g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL); - - debug_log ("non-connected with external display"); - - player->is_subtitle_force_drop = FALSE; - } - } -} - -gboolean -__mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @ -{ - mm_player_t* player = (mm_player_t*) data; - gboolean ret = TRUE; - static gboolean async_done = FALSE; - - return_val_if_fail ( player, FALSE ); - return_val_if_fail ( msg && GST_IS_MESSAGE(msg), FALSE ); - - switch ( GST_MESSAGE_TYPE( msg ) ) - { - case GST_MESSAGE_UNKNOWN: - debug_log("unknown message received\n"); - break; - - case GST_MESSAGE_EOS: - { - MMHandleType attrs = 0; - gint count = 0; - - debug_log("GST_MESSAGE_EOS received\n"); - - /* NOTE : EOS event is comming multiple time. watch out it */ - /* check state. we only process EOS when pipeline state goes to PLAYING */ - if ( ! (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) ) - { - debug_log("EOS received on non-playing state. ignoring it\n"); - break; - } - - __mmplayer_drop_subtitle(player, TRUE); - - if ( (player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) - { - GstPad *pad = NULL; - - pad = gst_element_get_static_pad (player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink"); - - debug_log("release audio callback\n"); - - /* release audio callback */ - gst_pad_remove_probe (pad, player->audio_cb_probe_id); - player->audio_cb_probe_id = 0; - /* audio callback should be free because it can be called even though probe remove.*/ - player->audio_stream_cb = NULL; - player->audio_stream_cb_user_param = NULL; - - } - - /* rewind if repeat count is greater then zero */ - /* get play count */ - attrs = MMPLAYER_GET_ATTRS(player); - - if ( attrs ) - { - gboolean smooth_repeat = FALSE; - - mm_attrs_get_int_by_name(attrs, "profile_play_count", &count); - mm_attrs_get_int_by_name(attrs, "profile_smooth_repeat", &smooth_repeat); - - player->play_count = count; - - debug_log("remaining play count: %d, playback rate: %f\n", count, player->playback_rate); - - if ( count > 1 || count == -1 || player->playback_rate < 0.0 ) /* default value is 1 */ - { - if ( smooth_repeat ) - { - debug_log("smooth repeat enabled. seeking operation will be excuted in new thread\n"); - - g_cond_signal( &player->repeat_thread_cond ); - - break; - } - else - { - gint ret_value = 0; - - if ( player->section_repeat ) - { - ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end); - } - else - { - if ( player->playback_rate < 0.0 ) - { - player->resumed_by_rewind = TRUE; - _mmplayer_set_mute((MMHandleType)player, 0); - MMPLAYER_POST_MSG( player, MM_MESSAGE_RESUMED_BY_REW, NULL ); - } - - __mmplayer_handle_eos_delay( player, player->ini.delay_before_repeat ); - - /* initialize */ - player->sent_bos = FALSE; - } - - if ( MM_ERROR_NONE != ret_value ) - { - debug_error("failed to set position to zero for rewind\n"); - } - - /* not posting eos when repeating */ - break; - } - } - } - - MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-eos" ); - - /* post eos message to application */ - __mmplayer_handle_eos_delay( player, player->ini.eos_delay ); - - /* reset last position */ - player->last_position = 0; - } - break; - - case GST_MESSAGE_ERROR: - { - GError *error = NULL; - gchar* debug = NULL; - - /* generating debug info before returning error */ - MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-error" ); - - /* get error code */ - gst_message_parse_error( msg, &error, &debug ); - - if ( gst_structure_has_name ( gst_message_get_structure(msg), "streaming_error" ) ) - { - /* Note : the streaming error from the streaming source is handled - * using __mmplayer_handle_streaming_error. - */ - __mmplayer_handle_streaming_error ( player, msg ); - - /* dump state of all element */ - __mmplayer_dump_pipeline_state( player ); - } - else - { - /* traslate gst error code to msl error code. then post it - * to application if needed - */ - __mmplayer_handle_gst_error( player, msg, error ); - - if (debug) - { - debug_error ("error debug : %s", debug); - } - - } - - if (MMPLAYER_IS_HTTP_PD(player)) - { - _mmplayer_unrealize_pd_downloader ((MMHandleType)player); - } - - MMPLAYER_FREEIF( debug ); - g_error_free( error ); - } - break; - - case GST_MESSAGE_WARNING: - { - char* debug = NULL; - GError* error = NULL; - - gst_message_parse_warning(msg, &error, &debug); - - debug_log("warning : %s\n", error->message); - debug_log("debug : %s\n", debug); - - MMPLAYER_POST_MSG( player, MM_MESSAGE_WARNING, NULL ); - - MMPLAYER_FREEIF( debug ); - g_error_free( error ); - } - break; - - case GST_MESSAGE_TAG: - { - debug_log("GST_MESSAGE_TAG\n"); - if ( ! __mmplayer_gst_extract_tag_from_msg( player, msg ) ) - { - debug_warning("failed to extract tags from gstmessage\n"); - } - } - break; - - case GST_MESSAGE_BUFFERING: - { - MMMessageParamType msg_param = {0, }; - - if (!MMPLAYER_IS_STREAMING(player)) - break; - - /* ignore the prev buffering message */ - if ((player->streamer) && (player->streamer->is_buffering == FALSE) && (player->streamer->is_buffering_done == TRUE)) - { - gint buffer_percent = 0; - - gst_message_parse_buffering (msg, &buffer_percent); - - if (buffer_percent == MAX_BUFFER_PERCENT) - { - debug_log ("Ignored all the previous buffering msg! (got %d%%)\n", buffer_percent); - player->streamer->is_buffering_done = FALSE; - } - - break; - } - - __mmplayer_update_buffer_setting(player, msg); - - __mmplayer_handle_buffering_message ( player ); - - msg_param.connection.buffering = player->streamer->buffering_percent; - MMPLAYER_POST_MSG ( player, MM_MESSAGE_BUFFERING, &msg_param ); - if (MMPLAYER_IS_RTSP_STREAMING(player) && (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) - { - if (player->doing_seek) - { - if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) - { - player->doing_seek = FALSE; - MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL ); - } - else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) - { - async_done = TRUE; - } - } - } - } - break; - - case GST_MESSAGE_STATE_CHANGED: - { - MMPlayerGstElement *mainbin; - const GValue *voldstate, *vnewstate, *vpending; - GstState oldstate, newstate, pending; - - if ( ! ( player->pipeline && player->pipeline->mainbin ) ) - { - debug_error("player pipeline handle is null"); - break; - } - - mainbin = player->pipeline->mainbin; - - /* we only handle messages from pipeline */ - if( msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst ) - break; - - /* get state info from msg */ - voldstate = gst_structure_get_value (gst_message_get_structure(msg), "old-state"); - vnewstate = gst_structure_get_value (gst_message_get_structure(msg), "new-state"); - vpending = gst_structure_get_value (gst_message_get_structure(msg), "pending-state"); - - oldstate = (GstState)voldstate->data[0].v_int; - newstate = (GstState)vnewstate->data[0].v_int; - pending = (GstState)vpending->data[0].v_int; - - debug_log("state changed [%s] : %s ---> %s final : %s\n", - GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), - gst_element_state_get_name( (GstState)oldstate ), - gst_element_state_get_name( (GstState)newstate ), - gst_element_state_get_name( (GstState)pending ) ); - - if (oldstate == newstate) - { - debug_log("pipeline reports state transition to old state"); - break; - } - - switch(newstate) - { - case GST_STATE_VOID_PENDING: - break; - - case GST_STATE_NULL: - break; - - case GST_STATE_READY: - break; - - case GST_STATE_PAUSED: - { - gboolean prepare_async = FALSE; - gboolean is_drm = FALSE; - - if ( ! player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex) - __mmplayer_configure_audio_callback(player); - - if ( ! player->sent_bos && oldstate == GST_STATE_READY) // managed prepare async case - { - mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async); - debug_log("checking prepare mode for async transition - %d", prepare_async); - } - - if ( MMPLAYER_IS_STREAMING(player) || prepare_async ) - { - MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PAUSED ); - - if (MMPLAYER_IS_STREAMING(player) && (player->streamer)) - { - __mm_player_streaming_set_content_bitrate(player->streamer, - player->total_maximum_bitrate, player->total_bitrate); - } - } - - /* NOTE : should consider streaming case */ - /* check if drm file */ - if ((player->pipeline->mainbin[MMPLAYER_M_SRC].gst) && - (g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm"))) - { - g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm", &is_drm, NULL); - - if (is_drm) - { - player->is_drm_file = TRUE; - } - } - } - break; - - case GST_STATE_PLAYING: - { -/* for audio tunning */ -#ifndef IS_SDK - if (player->can_support_codec == 0x03) { - gint volume_type; - mm_attrs_get_int_by_name(player->attrs, "sound_volume_type", &volume_type); - volume_type |= MM_SOUND_VOLUME_GAIN_VIDEO; - g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "volumetype", volume_type, NULL); - } -#endif - if ( MMPLAYER_IS_STREAMING(player) ) // managed prepare async case when buffering is completed - { - // pending state should be reset oyherwise, it's still playing even though it's resumed after bufferging. - if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) || - (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING)) - { - MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PLAYING); - } - } - - if (player->gapless.stream_changed) - { - _mmplayer_update_content_attrs(player, ATTR_ALL); - } - - if (player->doing_seek && async_done) - { - player->doing_seek = FALSE; - async_done = FALSE; - MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL ); - } - } - break; - - default: - break; - } - } - break; - - case GST_MESSAGE_CLOCK_LOST: - { - GstClock *clock = NULL; - gst_message_parse_clock_lost (msg, &clock); - debug_log("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL")); - g_print ("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL")); - - if (((player->ini.provide_clock_for_music) && (!player->videodec_linked)) || - ((player->ini.provide_clock_for_movie) && (player->videodec_linked))) - { - debug_log ("Provide clock is TRUE, do pause->resume\n"); - __gst_pause(player, FALSE); - __gst_resume(player, FALSE); - } - } - break; - - case GST_MESSAGE_NEW_CLOCK: - { - GstClock *clock = NULL; - gst_message_parse_new_clock (msg, &clock); - debug_log("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL")); - } - break; - - case GST_MESSAGE_ELEMENT: - { - const gchar *structure_name; - gint count = 0; - MMHandleType attrs = 0; - - attrs = MMPLAYER_GET_ATTRS(player); - if ( !attrs ) - { - debug_error("cannot get content attribute"); - ret = FALSE; - break; - } - - if(gst_message_get_structure(msg) == NULL) - break; - - structure_name = gst_structure_get_name(gst_message_get_structure(msg)); - if(!strcmp(structure_name, "Language_list")) - { - const GValue *lang_list = NULL; - lang_list = gst_structure_get_value (gst_message_get_structure(msg), "lang_list"); - if(lang_list != NULL) - { - count = g_list_length((GList *)g_value_get_pointer (lang_list)); - if (count > 1) - debug_log("Total audio tracks (from parser) = %d \n",count); - } - } - - if (!strcmp (structure_name, "Ext_Sub_Language_List")) - { - const GValue *lang_list = NULL; - MMPlayerLangStruct *temp = NULL; - - lang_list = gst_structure_get_value (gst_message_get_structure(msg), "lang_list"); - if (lang_list != NULL) - { - count = g_list_length ((GList *)g_value_get_pointer (lang_list)); - if (count) - { - player->subtitle_language_list = (GList *)g_value_get_pointer (lang_list); - mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count); - if (mmf_attrs_commit (attrs)) - debug_error("failed to commit.\n"); - debug_log("Total subtitle tracks = %d \n", count); - } - while (count) - { - temp = g_list_nth_data (player->subtitle_language_list, count - 1); - debug_log ("value of lang_key is %s and lang_code is %s", - temp->language_key, temp->language_code); - count--; - } - } - } - - /* custom message */ - if (!strcmp (structure_name, "audio_codec_not_supported")) { - MMMessageParamType msg_param = {0,}; - msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND; - MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param); - } - } - break; - - case GST_MESSAGE_DURATION_CHANGED: - { - debug_log("GST_MESSAGE_DURATION_CHANGED\n"); - ret = __mmplayer_gst_handle_duration(player, msg); - if (!ret) - { - debug_warning("failed to update duration"); - } - } - - break; - - case GST_MESSAGE_ASYNC_START: - { - debug_log("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg))); - } - break; - - case GST_MESSAGE_ASYNC_DONE: - { - debug_log("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg))); - - /* we only handle messages from pipeline */ - if( msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst ) - break; - - if (player->doing_seek) - { - if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) - { - player->doing_seek = FALSE; - MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL ); - } - else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) - { - if ((MMPLAYER_IS_HTTP_STREAMING(player)) && - (player->streamer) && - (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) && - (player->streamer->is_buffering == FALSE)) - { - GstQuery *query = NULL; - gboolean busy = FALSE; - gint percent = 0; - - if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) - { - query = gst_query_new_buffering ( GST_FORMAT_PERCENT ); - if ( gst_element_query (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query ) ) - { - gst_query_parse_buffering_percent ( query, &busy, &percent); - } - gst_query_unref (query); - - debug_log("buffered percent(%s): %d\n", - GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent); - } - - if (percent >= 100) - { - player->streamer->is_buffering = FALSE; - __mmplayer_handle_buffering_message(player); - } - } - - async_done = TRUE; - } - } - } - break; - - #if 0 /* delete unnecessary logs */ - case GST_MESSAGE_REQUEST_STATE: debug_log("GST_MESSAGE_REQUEST_STATE\n"); break; - case GST_MESSAGE_STEP_START: debug_log("GST_MESSAGE_STEP_START\n"); break; - case GST_MESSAGE_QOS: debug_log("GST_MESSAGE_QOS\n"); break; - case GST_MESSAGE_PROGRESS: debug_log("GST_MESSAGE_PROGRESS\n"); break; - case GST_MESSAGE_ANY: debug_log("GST_MESSAGE_ANY\n"); break; - case GST_MESSAGE_INFO: debug_log("GST_MESSAGE_STATE_DIRTY\n"); break; - case GST_MESSAGE_STATE_DIRTY: debug_log("GST_MESSAGE_STATE_DIRTY\n"); break; - case GST_MESSAGE_STEP_DONE: debug_log("GST_MESSAGE_STEP_DONE\n"); break; - case GST_MESSAGE_CLOCK_PROVIDE: debug_log("GST_MESSAGE_CLOCK_PROVIDE\n"); break; - case GST_MESSAGE_STRUCTURE_CHANGE: debug_log("GST_MESSAGE_STRUCTURE_CHANGE\n"); break; - case GST_MESSAGE_STREAM_STATUS: debug_log("GST_MESSAGE_STREAM_STATUS\n"); break; - case GST_MESSAGE_APPLICATION: debug_log("GST_MESSAGE_APPLICATION\n"); break; - case GST_MESSAGE_SEGMENT_START: debug_log("GST_MESSAGE_SEGMENT_START\n"); break; - case GST_MESSAGE_SEGMENT_DONE: debug_log("GST_MESSAGE_SEGMENT_DONE\n"); break; - case GST_MESSAGE_LATENCY: debug_log("GST_MESSAGE_LATENCY\n"); break; - #endif - - default: - break; - } - - /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since - * gst_element_post_message api takes ownership of the message. - */ - //gst_message_unref( msg ); - - return ret; -} - -static gboolean -__mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg) -{ - gint64 bytes = 0; - - MMPLAYER_FENTER(); - - return_val_if_fail(player, FALSE); - return_val_if_fail(msg, FALSE); - - if ((MMPLAYER_IS_HTTP_STREAMING(player)) && - (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) - { - debug_log("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src))); - - if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) - { - debug_log("data total size of http content: %lld", bytes); - player->http_content_size = bytes; - } - } - else - { - /* handling audio clip which has vbr. means duration is keep changing */ - _mmplayer_update_content_attrs (player, ATTR_DURATION ); - } - - MMPLAYER_FLEAVE(); - - return TRUE; -} - - -static gboolean -__mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg) // @ -{ - -/* macro for better code readability */ -#define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \ -if (gst_tag_list_get_string(tag_list, gsttag, &string)) \ -{\ - if (string != NULL)\ - {\ - secure_debug_log ( "update tag string : %s\n", string); \ - mm_attrs_set_string_by_name(attribute, playertag, string); \ - g_free(string);\ - string = NULL;\ - }\ -} - -#define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \ -GstSample *sample = NULL;\ -if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample))\ -{\ - GstMapInfo info = GST_MAP_INFO_INIT;\ - buffer = gst_sample_get_buffer(sample);\ - if (!gst_buffer_map(buffer, &info, GST_MAP_READ)){\ - debug_log("failed to get image data from tag");\ - return FALSE;\ - }\ - secure_debug_log ( "update album cover data : %p, size : %d\n", info.data, info.size);\ - MMPLAYER_FREEIF(player->album_art); \ - player->album_art = (gchar *)g_malloc(info.size); \ - if (player->album_art) \ - { \ - memcpy(player->album_art, info.data, info.size); \ - mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size); \ - if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) \ - { \ - msg_param.data = (void *)player->album_art; \ - msg_param.size = info.size; \ - MMPLAYER_POST_MSG (player, MM_MESSAGE_IMAGE_BUFFER, &msg_param); \ - secure_debug_log ( "post message image buffer data : %p, size : %d\n", info.data, info.size); \ - } \ - } \ - gst_buffer_unmap(buffer, &info); \ -} - -#define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \ -if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint))\ -{\ - if(v_uint)\ - {\ - if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) \ - {\ - if (player->updated_bitrate_count == 0) \ - mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \ - if (player->updated_bitrate_countbitrate[player->updated_bitrate_count] = v_uint;\ - player->total_bitrate += player->bitrate[player->updated_maximum_bitrate_count]; \ - player->updated_bitrate_count++; \ - mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate);\ - secure_debug_log ( "update bitrate %d[bps] of stream #%d.\n", v_uint, player->updated_bitrate_count);\ - }\ - }\ - else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) \ - {\ - if (player->updated_maximum_bitrate_countmaximum_bitrate[player->updated_maximum_bitrate_count] = v_uint;\ - player->total_maximum_bitrate += player->maximum_bitrate[player->updated_maximum_bitrate_count]; \ - player->updated_maximum_bitrate_count++; \ - mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate); \ - secure_debug_log ( "update maximum bitrate %d[bps] of stream #%d\n", v_uint, player->updated_maximum_bitrate_count);\ - }\ - }\ - else\ - {\ - mm_attrs_set_int_by_name(attribute, playertag, v_uint); \ - }\ - v_uint = 0;\ - }\ -} - -#define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \ -if (gst_tag_list_get_date(tag_list, gsttag, &date))\ -{\ - if (date != NULL)\ - {\ - string = g_strdup_printf("%d", g_date_get_year(date));\ - mm_attrs_set_string_by_name(attribute, playertag, string);\ - secure_debug_log ( "metainfo year : %s\n", string);\ - MMPLAYER_FREEIF(string);\ - g_date_free(date);\ - }\ -} - -#define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \ -if(gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64))\ -{\ - if(v_uint64)\ - {\ - /* FIXIT : don't know how to store date */\ - g_assert(1);\ - v_uint64 = 0;\ - }\ -} - -#define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \ -if(gst_tag_list_get_double(tag_list, gsttag, &v_double))\ -{\ - if(v_double)\ - {\ - /* FIXIT : don't know how to store date */\ - g_assert(1);\ - v_double = 0;\ - }\ -} - - /* function start */ - GstTagList* tag_list = NULL; - - MMHandleType attrs = 0; - - char *string = NULL; - guint v_uint = 0; - GDate *date = NULL; - /* album cover */ - GstBuffer *buffer = NULL; - gint index = 0; - MMMessageParamType msg_param = {0, }; - - /* currently not used. but those are needed for above macro */ - //guint64 v_uint64 = 0; - //gdouble v_double = 0; - - return_val_if_fail( player && msg, FALSE ); - - attrs = MMPLAYER_GET_ATTRS(player); - - return_val_if_fail( attrs, FALSE ); - - /* get tag list from gst message */ - gst_message_parse_tag(msg, &tag_list); - - /* store tags to player attributes */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title"); - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist"); - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album"); - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author"); - MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date"); - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre"); - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */ - MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num"); - /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description"); - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright"); - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec"); - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec"); - MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate"); - MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate"); - MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover"); - /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation"); - - if ( mmf_attrs_commit ( attrs ) ) - debug_error("failed to commit.\n"); - - gst_tag_list_free(tag_list); - - return TRUE; -} - -static void -__mmplayer_gst_rtp_no_more_pads (GstElement *element, gpointer data) // @ -{ - mm_player_t* player = (mm_player_t*) data; - - MMPLAYER_FENTER(); - - /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever - * we connect autoplugging element to the pad which is just added to rtspsrc, we increase - * num_dynamic_pad. and this is no-more-pad situation which means mo more pad will be added. - * So we can say this. if num_dynamic_pad is zero, it must be one of followings - - * [1] audio and video will be dumped with filesink. - * [2] autoplugging is done by just using pad caps. - * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal - * and the video will be dumped via filesink. - */ - if ( player->num_dynamic_pad == 0 ) - { - debug_log("it seems pad caps is directely used for autoplugging. removing fakesink now\n"); - - if ( ! __mmplayer_gst_remove_fakesink( player, - &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]) ) - { - /* NOTE : __mmplayer_pipeline_complete() can be called several time. because - * signaling mechanism ( pad-added, no-more-pad, new-decoded-pad ) from various - * source element are not same. To overcome this situation, this function will called - * several places and several times. Therefore, this is not an error case. - */ - return; - } - } - - /* create dot before error-return. for debugging */ - MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-no-more-pad" ); - - player->no_more_pad = TRUE; - - MMPLAYER_FLEAVE(); -} - -static gboolean -__mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink) // @ -{ - GstElement* parent = NULL; - - return_val_if_fail(player && player->pipeline, FALSE); - - /* if we have no fakesink. this meas we are using decodebin which doesn' - t need to add extra fakesink */ - return_val_if_fail(fakesink, TRUE); - - /* lock */ - g_mutex_lock(&player->fsink_lock ); - - if ( ! fakesink->gst ) - { - goto ERROR; - } - - /* get parent of fakesink */ - parent = (GstElement*)gst_object_get_parent( (GstObject*)fakesink->gst ); - if ( ! parent ) - { - debug_log("fakesink already removed\n"); - goto ERROR; - } - - gst_element_set_locked_state( fakesink->gst, TRUE ); - - /* setting the state to NULL never returns async - * so no need to wait for completion of state transiton - */ - if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (fakesink->gst, GST_STATE_NULL) ) - { - debug_error("fakesink state change failure!\n"); - - /* FIXIT : should I return here? or try to proceed to next? */ - /* return FALSE; */ - } - - /* remove fakesink from it's parent */ - if ( ! gst_bin_remove( GST_BIN( parent ), fakesink->gst ) ) - { - debug_error("failed to remove fakesink\n"); - - gst_object_unref( parent ); - - goto ERROR; - } - - gst_object_unref( parent ); - - debug_log("state-holder removed\n"); - - gst_element_set_locked_state( fakesink->gst, FALSE ); - - g_mutex_unlock( &player->fsink_lock ); - return TRUE; - -ERROR: - if ( fakesink->gst ) - { - gst_element_set_locked_state( fakesink->gst, FALSE ); - } - - g_mutex_unlock( &player->fsink_lock ); - return FALSE; -} - - -static void -__mmplayer_gst_rtp_dynamic_pad (GstElement *element, GstPad *pad, gpointer data) // @ -{ - GstPad *sinkpad = NULL; - GstCaps* caps = NULL; - GstElement* new_element = NULL; - GstStructure* str = NULL; - const gchar* name = NULL; - - mm_player_t* player = (mm_player_t*) data; - - MMPLAYER_FENTER(); - - return_if_fail( element && pad ); - return_if_fail( player && - player->pipeline && - player->pipeline->mainbin ); - - - /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation. - * num_dynamic_pad will decreased after creating a sinkbin. - */ - player->num_dynamic_pad++; - debug_log("stream count inc : %d\n", player->num_dynamic_pad); - - /* perform autoplugging if dump is disabled */ - if ( player->ini.rtsp_do_typefinding ) - { - /* create typefind */ - new_element = gst_element_factory_make( "typefind", NULL ); - if ( ! new_element ) - { - debug_error("failed to create typefind\n"); - goto ERROR; - } - - MMPLAYER_SIGNAL_CONNECT( player, - G_OBJECT(new_element), - MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, - "have-type", - G_CALLBACK(__mmplayer_typefind_have_type), - (gpointer)player); - - /* FIXIT : try to remove it */ - player->have_dynamic_pad = FALSE; - } - else /* NOTE : use pad's caps directely. if enabled. what I am assuming is there's no elemnt has dynamic pad */ - { - debug_log("using pad caps to autopluging instead of doing typefind\n"); - - caps = gst_pad_query_caps( pad, NULL ); - - MMPLAYER_CHECK_NULL( caps ); - - /* clear previous result*/ - player->have_dynamic_pad = FALSE; - - str = gst_caps_get_structure(caps, 0); - - if ( ! str ) - { - debug_error ("cannot get structure from caps.\n"); - goto ERROR; - } - - name = gst_structure_get_name (str); - if ( ! name ) - { - debug_error ("cannot get mimetype from structure.\n"); - goto ERROR; - } - - if (strstr(name, "video")) - { - gint stype = 0; - mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype); - - if (stype == MM_DISPLAY_SURFACE_NULL) - { - if (player->v_stream_caps) - { - gst_caps_unref(player->v_stream_caps); - player->v_stream_caps = NULL; - } - - new_element = gst_element_factory_make("fakesink", NULL); - player->num_dynamic_pad--; - goto NEW_ELEMENT; - } - } - - /* clear previous result*/ - player->have_dynamic_pad = FALSE; - - if ( !__mmplayer_try_to_plug_decodebin(player, pad, caps)) - { - debug_error("failed to autoplug for caps"); - goto ERROR; - } - - /* check if there's dynamic pad*/ - if( player->have_dynamic_pad ) - { - debug_error("using pad caps assums there's no dynamic pad !\n"); - debug_error("try with enalbing rtsp_do_typefinding\n"); - goto ERROR; - } - - gst_caps_unref( caps ); - caps = NULL; - } - - NEW_ELEMENT: - - /* excute new_element if created*/ - if ( new_element ) - { - debug_log("adding new element to pipeline\n"); - - /* set state to READY before add to bin */ - MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_READY ); - - /* add new element to the pipeline */ - if ( FALSE == gst_bin_add( GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element) ) - { - debug_error("failed to add autoplug element to bin\n"); - goto ERROR; - } - - /* get pad from element */ - sinkpad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "sink" ); - if ( !sinkpad ) - { - debug_error("failed to get sinkpad from autoplug element\n"); - goto ERROR; - } - - /* link it */ - if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) ) - { - debug_error("failed to link autoplug element\n"); - goto ERROR; - } - - gst_object_unref (sinkpad); - sinkpad = NULL; - - /* run. setting PLAYING here since streamming source is live source */ - MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_PLAYING ); - } - - MMPLAYER_FLEAVE(); - - return; - -STATE_CHANGE_FAILED: -ERROR: - /* FIXIT : take care if new_element has already added to pipeline */ - if ( new_element ) - gst_object_unref(GST_OBJECT(new_element)); - - if ( sinkpad ) - gst_object_unref(GST_OBJECT(sinkpad)); - - if ( caps ) - gst_object_unref(GST_OBJECT(caps)); - - /* FIXIT : how to inform this error to MSL ????? */ - /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and - * then post an error to application - */ -} - - - -/* FIXIT : check indent */ -#if 0 -static void -__mmplayer_gst_wfd_dynamic_pad (GstElement *element, GstPad *pad, gpointer data) // @ -{ - GstPad *sinkpad = NULL; - GstCaps* caps = NULL; - GstElement* new_element = NULL; - enum MainElementID element_id = MMPLAYER_M_NUM; - - mm_player_t* player = (mm_player_t*) data; - - MMPLAYER_FENTER(); - - return_if_fail( element && pad ); - return_if_fail( player && - player->pipeline && - player->pipeline->mainbin ); - - debug_log("stream count inc : %d\n", player->num_dynamic_pad); - - { - debug_log("using pad caps to autopluging instead of doing typefind\n"); - caps = gst_pad_query_caps( pad ); - MMPLAYER_CHECK_NULL( caps ); - /* clear previous result*/ - player->have_dynamic_pad = FALSE; - new_element = gst_element_factory_make("rtpmp2tdepay", "wfd_rtp_depay"); - if ( !new_element ) - { - debug_error ( "failed to create wfd rtp depay element\n" ); - goto ERROR; - } - MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_READY ); - /* add new element to the pipeline */ - if ( FALSE == gst_bin_add( GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element) ) - { - debug_log("failed to add autoplug element to bin\n"); - goto ERROR; - } - /* get pad from element */ - sinkpad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "sink" ); - if ( !sinkpad ) - { - debug_log("failed to get sinkpad from autoplug element\n"); - goto ERROR; - } - /* link it */ - if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) ) - { - debug_log("failed to link autoplug element\n"); - goto ERROR; - } - gst_object_unref (sinkpad); - sinkpad = NULL; - pad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "src" ); - caps = gst_pad_query_caps( pad ); - MMPLAYER_CHECK_NULL( caps ); - MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_PLAYING ); - /* create typefind */ - new_element = gst_element_factory_make( "typefind", NULL ); - if ( ! new_element ) - { - debug_log("failed to create typefind\n"); - goto ERROR; - } - - MMPLAYER_SIGNAL_CONNECT( player, - G_OBJECT(new_element), - MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, - "have-type", - G_CALLBACK(__mmplayer_typefind_have_type), - (gpointer)player); - - player->have_dynamic_pad = FALSE; - } - - /* excute new_element if created*/ - if ( new_element ) - { - debug_log("adding new element to pipeline\n"); - - /* set state to READY before add to bin */ - MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_READY ); - - /* add new element to the pipeline */ - if ( FALSE == gst_bin_add( GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element) ) - { - debug_log("failed to add autoplug element to bin\n"); - goto ERROR; - } - - /* get pad from element */ - sinkpad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "sink" ); - if ( !sinkpad ) - { - debug_log("failed to get sinkpad from autoplug element\n"); - goto ERROR; - } - - /* link it */ - if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) ) - { - debug_log("failed to link autoplug element\n"); - goto ERROR; - } - - gst_object_unref (sinkpad); - sinkpad = NULL; - - /* run. setting PLAYING here since streamming source is live source */ - MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_PLAYING ); - } - - /* store handle to futher manipulation */ - player->pipeline->mainbin[element_id].id = element_id; - player->pipeline->mainbin[element_id].gst = new_element; - - MMPLAYER_FLEAVE(); - - return; - -STATE_CHANGE_FAILED: -ERROR: - /* FIXIT : take care if new_element has already added to pipeline */ - if ( new_element ) - gst_object_unref(GST_OBJECT(new_element)); - - if ( sinkpad ) - gst_object_unref(GST_OBJECT(sinkpad)); - - if ( caps ) - gst_object_unref(GST_OBJECT(caps)); - - /* FIXIT : how to inform this error to MSL ????? */ - /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and - * then post an error to application - */ -} -#endif - -static GstPadProbeReturn -__mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data) -{ - debug_log ("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad)); - return GST_PAD_PROBE_OK; -} - -static GstPadProbeReturn -__mmplayer_audio_data_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data) -{ - mm_player_t* player = (mm_player_t*) u_data; - GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info); - - /* TO_CHECK: performance */ - return_val_if_fail (player && GST_IS_BUFFER(pad_buffer), GST_PAD_PROBE_OK); - - if (GST_BUFFER_PTS_IS_VALID(pad_buffer) && GST_BUFFER_DURATION_IS_VALID(pad_buffer)) - player->gapless.next_pts = GST_BUFFER_PTS(pad_buffer) + GST_BUFFER_DURATION(pad_buffer); - - return GST_PAD_PROBE_OK; -} - -static GstPadProbeReturn -__mmplayer_gst_selector_event_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data) -{ - GstPadProbeReturn ret = GST_PAD_PROBE_OK; - GstEvent *event = GST_PAD_PROBE_INFO_DATA (info); - mm_player_t* player = (mm_player_t*)data; - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_STREAM_START: - break; - case GST_EVENT_SEGMENT: { - GstSegment segment; - GstEvent *tmpev; - - if (!player->gapless.running) - break; - - if (player->gapless.stream_changed) { - player->gapless.start_time += player->gapless.next_pts; - player->gapless.stream_changed = FALSE; - } - - debug_log ("event: %" GST_PTR_FORMAT, event); - gst_event_copy_segment (event, &segment); - - if (segment.format == GST_FORMAT_TIME) - { - segment.base = player->gapless.start_time; - debug_log ("base of segment: %" GST_TIME_FORMAT, GST_TIME_ARGS (segment.base)); - - tmpev = gst_event_new_segment (&segment); - gst_event_set_seqnum (tmpev, gst_event_get_seqnum (event)); - gst_event_unref (event); - GST_PAD_PROBE_INFO_DATA(info) = tmpev; - } - break; - } - default: - break; - } - return ret; -} - -static void -__mmplayer_gst_decode_pad_added (GstElement *elem, GstPad *pad, gpointer data) -{ - mm_player_t* player = NULL; - GstElement* pipeline = NULL; - GstElement* selector = NULL; - GstElement* fakesink = NULL; - GstCaps* caps = NULL; - GstStructure* str = NULL; - const gchar* name = NULL; - GstPad* sinkpad = NULL; - GstPad* srcpad = NULL; - gboolean first_track = FALSE; - - enum MainElementID elemId = MMPLAYER_M_NUM; - MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO; - - /* check handles */ - player = (mm_player_t*)data; - - return_if_fail (elem && pad); - return_if_fail (player && player->pipeline && player->pipeline->mainbin); - - //debug_log ("pad-added signal handling\n"); - - pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst; - - /* get mimetype from caps */ - caps = gst_pad_query_caps (pad, NULL); - if ( !caps ) - { - debug_error ("cannot get caps from pad.\n"); - goto ERROR; - } - - str = gst_caps_get_structure (caps, 0); - if ( ! str ) - { - debug_error ("cannot get structure from caps.\n"); - goto ERROR; - } - - name = gst_structure_get_name (str); - if ( ! name ) - { - debug_error ("cannot get mimetype from structure.\n"); - goto ERROR; - } - - MMPLAYER_LOG_GST_CAPS_TYPE(caps); - //debug_log ("detected mimetype : %s\n", name); - - if (strstr(name, "video")) - { - gint stype = 0; - mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype); - - /* don't make video because of not required, and not support multiple track */ - if (stype == MM_DISPLAY_SURFACE_NULL) - { - debug_log ("no video sink by null surface or multiple track"); - gchar *caps_str = gst_caps_to_string(caps); - if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12")) - { - player->set_mode.video_zc = TRUE; - } - MMPLAYER_FREEIF( caps_str ); - - if (player->v_stream_caps) - { - gst_caps_unref(player->v_stream_caps); - player->v_stream_caps = NULL; - } - - debug_log ("create fakesink instead of videobin"); - - /* fake sink */ - fakesink = gst_element_factory_make ("fakesink", NULL); - if (fakesink == NULL) - { - debug_error ("ERROR : fakesink create error\n"); - goto ERROR; - } - - player->video_fakesink = fakesink; - - gst_bin_add (GST_BIN(pipeline), fakesink); - - // link - sinkpad = gst_element_get_static_pad (fakesink, "sink"); - - if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) - { - debug_warning ("failed to link fakesink\n"); - gst_object_unref (GST_OBJECT(fakesink)); - goto ERROR; - } - - if (player->set_mode.media_packet_video_stream) - player->video_cb_probe_id = gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_BUFFER, __mmplayer_video_stream_probe, player, NULL); - - g_object_set (G_OBJECT (fakesink), "async", TRUE, NULL); - g_object_set (G_OBJECT (fakesink), "sync", TRUE, NULL); - gst_element_set_state (fakesink, GST_STATE_PAUSED); - - goto DONE; - } - __mmplayer_gst_decode_callback (elem, pad, player); - } - else - { - if (strstr(name, "audio")) - { - gint samplerate = 0; - gint channels = 0; - - if (MMPLAYER_IS_ES_BUFF_SRC(player)) - { - __mmplayer_gst_decode_callback (elem, pad, player); - return; - } - - debug_log ("audio selector \n"); - elemId = MMPLAYER_M_A_INPUT_SELECTOR; - stream_type = MM_PLAYER_TRACK_TYPE_AUDIO; - - gst_structure_get_int (str, "rate", &samplerate); - gst_structure_get_int (str, "channels", &channels); - - if ((channels > 0 && samplerate == 0)) {//exclude audio decoding - /* fake sink */ - fakesink = gst_element_factory_make ("fakesink", NULL); - if (fakesink == NULL) - { - debug_error ("ERROR : fakesink create error\n"); - goto ERROR; - } - - gst_bin_add (GST_BIN(pipeline), fakesink); - - /* link */ - sinkpad = gst_element_get_static_pad (fakesink, "sink"); - - if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) - { - debug_warning ("failed to link fakesink\n"); - gst_object_unref (GST_OBJECT(fakesink)); - goto ERROR; - } - - g_object_set (G_OBJECT (fakesink), "async", TRUE, NULL); - g_object_set (G_OBJECT (fakesink), "sync", TRUE, NULL); - gst_element_set_state (fakesink, GST_STATE_PAUSED); - - goto DONE; - } - } - else if (strstr(name, "text")) - { - debug_log ("text selector \n"); - elemId = MMPLAYER_M_T_INPUT_SELECTOR; - stream_type = MM_PLAYER_TRACK_TYPE_TEXT; - } - else - { - debug_error ("wrong elem id \n"); - goto ERROR; - } - } - - if(strstr(name, "video")) - return; - - selector = player->pipeline->mainbin[elemId].gst; - - if (selector == NULL) - { - selector = gst_element_factory_make ("input-selector", NULL); - debug_log ("Creating input-selector\n"); - if (selector == NULL) - { - debug_error ("ERROR : input-selector create error\n"); - goto ERROR; - } - g_object_set (selector, "sync-streams", TRUE, NULL); - - player->pipeline->mainbin[elemId].id = elemId; - player->pipeline->mainbin[elemId].gst = selector; - - first_track = TRUE; - // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default - - srcpad = gst_element_get_static_pad (selector, "src"); - - debug_log ("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad)); - player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, - __mmplayer_gst_selector_blocked, NULL, NULL); - player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, - __mmplayer_gst_selector_event_probe, player, NULL); - - gst_element_set_state (selector, GST_STATE_PAUSED); - gst_bin_add (GST_BIN(pipeline), selector); - } - else - { - debug_log ("input-selector is already created.\n"); - selector = player->pipeline->mainbin[elemId].gst; - } - - // link - debug_log ("Calling request pad with selector %p \n", selector); - sinkpad = gst_element_get_request_pad (selector, "sink_%u"); - - debug_log ("got pad %s:%s from selector", GST_DEBUG_PAD_NAME (sinkpad)); - - if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) - { - debug_warning ("failed to link selector\n"); - gst_object_unref (GST_OBJECT(selector)); - goto ERROR; - } - - if (first_track) - { - debug_log ("this is first track --> active track \n"); - g_object_set (selector, "active-pad", sinkpad, NULL); - } - - _mmplayer_track_update_info(player, stream_type, sinkpad); - - -DONE: -ERROR: - - if (caps) - { - gst_caps_unref (caps); - } - - if (sinkpad) - { - gst_object_unref (GST_OBJECT(sinkpad)); - sinkpad = NULL; - } - - if (srcpad) - { - gst_object_unref (GST_OBJECT(srcpad)); - srcpad = NULL; - } - - return; -} - -static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector) -{ - GstPad* srcpad = NULL; - MMHandleType attrs = 0; - gint active_index = 0; - - // [link] input-selector :: textbin - srcpad = gst_element_get_static_pad (text_selector, "src"); - if (!srcpad) - { - debug_error("failed to get srcpad from selector\n"); - return; - } - - debug_log ("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad)); - - active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index; - if ((active_index != DEFAULT_TRACK) && - (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) - { - debug_warning("failed to change text track\n"); - player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK; - } - - player->no_more_pad = TRUE; - __mmplayer_gst_decode_callback (text_selector, srcpad, player); - - debug_log ("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad)); - if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) - { - gst_pad_remove_probe (srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id); - player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0; - } - - debug_log("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num); - - if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0) - player->has_closed_caption = TRUE; - - attrs = MMPLAYER_GET_ATTRS(player); - if ( attrs ) - { - mm_attrs_set_int_by_name(attrs, "content_text_track_num",(gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num); - if (mmf_attrs_commit (attrs)) - debug_error("failed to commit.\n"); - } - else - { - debug_error("cannot get content attribute"); - } - - if (srcpad) - { - gst_object_unref ( GST_OBJECT(srcpad) ); - srcpad = NULL; - } -} - -int _mmplayer_gst_set_audio_channel(MMHandleType hplayer, MMPlayerAudioChannel ch_idx) -{ - int result = MM_ERROR_NONE; - - mm_player_t* player = (mm_player_t*)hplayer; - MMPlayerGstElement* mainbin = NULL; - gchar* change_pad_name = NULL; - GstPad* sinkpad = NULL; - GstCaps* caps = NULL; - - MMPLAYER_FENTER(); - - return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - debug_log ("Change Audio mode to %d\n", ch_idx); - player->use_deinterleave = TRUE; - - if ((!player->pipeline) || (!player->pipeline->mainbin)) - { - debug_log ("pre setting : %d\n", ch_idx); - - player->audio_mode.active_pad_index = ch_idx; - return result; - } - - mainbin = player->pipeline->mainbin; - - if (mainbin[MMPLAYER_M_A_SELECTOR].gst == NULL) - { - if (player->max_audio_channels < 2) - { - debug_log ("mono channel track only\n"); - return result; - } - - debug_warning ("selector doesn't exist\n"); - return result; /* keep playing */ - } - - debug_log ("total_ch_num : %d\n", player->audio_mode.total_track_num); - - if (player->audio_mode.total_track_num < 2) - { - debug_warning ("there is no another audio path\n"); - return result; /* keep playing */ - } - - if ((ch_idx < 0) || (ch_idx >= player->audio_mode.total_track_num)) - { - debug_warning ("Not a proper ch_idx : %d \n", ch_idx); - return result; /* keep playing */ - } - - /*To get the new pad from the selector*/ - change_pad_name = g_strdup_printf ("sink%d", ch_idx); - if (change_pad_name == NULL) - { - debug_warning ("Pad does not exists\n"); - goto ERROR; /* keep playing */ - } - - debug_log ("new active pad name: %s\n", change_pad_name); - - sinkpad = gst_element_get_static_pad (mainbin[MMPLAYER_M_A_SELECTOR].gst, change_pad_name); - if (sinkpad == NULL) - { - //result = MM_ERROR_PLAYER_INTERNAL; - goto ERROR; /* keep playing */ - } - - debug_log ("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad)); - g_object_set (mainbin[MMPLAYER_M_A_SELECTOR].gst, "active-pad", sinkpad, NULL); - - caps = gst_pad_get_current_caps(sinkpad); - MMPLAYER_LOG_GST_CAPS_TYPE(caps); - - __mmplayer_set_audio_attrs (player, caps); - player->audio_mode.active_pad_index = ch_idx; - -ERROR: - - if (sinkpad) - gst_object_unref (sinkpad); - - MMPLAYER_FREEIF(change_pad_name); - - MMPLAYER_FLEAVE(); - return result; -} - - - -static void -__mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data) -{ - mm_player_t* player = (mm_player_t*)data; - GstElement* selector = NULL; - GstElement* queue = NULL; - - GstPad* srcpad = NULL; - GstPad* sinkpad = NULL; - gchar* caps_str= NULL; - - MMPLAYER_FENTER(); - return_if_fail (player && player->pipeline && player->pipeline->mainbin); - - caps_str = gst_caps_to_string(gst_pad_get_current_caps(pad)); - debug_log ("deinterleave new caps : %s\n", caps_str); - MMPLAYER_FREEIF(caps_str); - - if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) - { - debug_error ("ERROR : queue create error\n"); - goto ERROR; - } - - g_object_set(G_OBJECT(queue), - "max-size-buffers", 10, - "max-size-bytes", 0, - "max-size-time", (guint64)0, - NULL); - - selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst; - - if (!selector) - { - debug_error("there is no audio channel selector.\n"); - goto ERROR; - } - - srcpad = gst_element_get_static_pad (queue, "src"); - sinkpad = gst_element_get_request_pad (selector, "sink_%u"); - - debug_log ("link (%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad)); - - if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) - { - debug_warning ("failed to link deinterleave - selector\n"); - goto ERROR; - } - - gst_element_set_state (queue, GST_STATE_PAUSED); - player->audio_mode.total_track_num++; - -ERROR: - - if (srcpad) - { - gst_object_unref ( GST_OBJECT(srcpad) ); - srcpad = NULL; - } - - if (sinkpad) - { - gst_object_unref ( GST_OBJECT(sinkpad) ); - sinkpad = NULL; - } - - MMPLAYER_FLEAVE(); - return; -} - -static void -__mmplayer_gst_deinterleave_no_more_pads (GstElement *elem, gpointer data) -{ - mm_player_t* player = NULL; - GstElement* selector = NULL; - GstPad* sinkpad = NULL; - gint active_index = 0; - gchar* change_pad_name = NULL; - GstCaps* caps = NULL; // no need to unref - - MMPLAYER_FENTER(); - player = (mm_player_t*) data; - - selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst; - - if (!selector) - { - debug_error("there is no audio channel selector.\n"); - goto ERROR; - } - - active_index = player->audio_mode.active_pad_index; - - if (active_index != DEFAULT_AUDIO_CH) - { - gint audio_ch = DEFAULT_AUDIO_CH; - - /*To get the new pad from the selector*/ - change_pad_name = g_strdup_printf ("sink%d", active_index); - if (change_pad_name != NULL) - { - sinkpad = gst_element_get_static_pad (selector, change_pad_name); - if (sinkpad != NULL) - { - debug_log ("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad)); - g_object_set (selector, "active-pad", sinkpad, NULL); - - audio_ch = active_index; - - caps = gst_pad_get_current_caps(sinkpad); - MMPLAYER_LOG_GST_CAPS_TYPE(caps); - - __mmplayer_set_audio_attrs (player, caps); - } - } - - player->audio_mode.active_pad_index = audio_ch; - debug_log("audio LR info (0:stereo) = %d\n", player->audio_mode.active_pad_index); - } - -ERROR: - - if (sinkpad) - gst_object_unref (sinkpad); - - MMPLAYER_FLEAVE(); - return; -} - -static void -__mmplayer_gst_build_deinterleave_path (GstElement *elem, GstPad *pad, gpointer data) -{ - mm_player_t* player = NULL; - MMPlayerGstElement *mainbin = NULL; - - GstElement* tee = NULL; - GstElement* stereo_queue = NULL; - GstElement* mono_queue = NULL; - GstElement* conv = NULL; - GstElement* filter = NULL; - GstElement* deinterleave = NULL; - GstElement* selector = NULL; - - GstPad* srcpad = NULL; - GstPad* selector_srcpad = NULL; - GstPad* sinkpad = NULL; - GstCaps* caps = NULL; - gulong block_id = 0; - - MMPLAYER_FENTER(); - - /* check handles */ - player = (mm_player_t*) data; - - return_if_fail( elem && pad ); - return_if_fail( player && player->pipeline && player->pipeline->mainbin ); - - mainbin = player->pipeline->mainbin; - - /* tee */ - if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) - { - debug_error ("ERROR : tee create error\n"); - goto ERROR; - } - - mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE; - mainbin[MMPLAYER_M_A_TEE].gst = tee; - - gst_element_set_state (tee, GST_STATE_PAUSED); - - /* queue */ - srcpad = gst_element_get_request_pad (tee, "src_%u"); - if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) - { - debug_error ("ERROR : stereo queue create error\n"); - goto ERROR; - } - - g_object_set(G_OBJECT(stereo_queue), - "max-size-buffers", 10, - "max-size-bytes", 0, - "max-size-time", (guint64)0, - NULL); - - player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1; - player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue; - - if (srcpad) - { - gst_object_unref (GST_OBJECT(srcpad)); - srcpad = NULL; - } - - srcpad = gst_element_get_request_pad (tee, "src_%u"); - - if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) - { - debug_error ("ERROR : mono queue create error\n"); - goto ERROR; - } - - g_object_set(G_OBJECT(mono_queue), - "max-size-buffers", 10, - "max-size-bytes", 0, - "max-size-time", (guint64)0, - NULL); - - player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2; - player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue; - - gst_element_set_state (stereo_queue, GST_STATE_PAUSED); - gst_element_set_state (mono_queue, GST_STATE_PAUSED); - - /* audioconvert */ - srcpad = gst_element_get_static_pad (mono_queue, "src"); - if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) - { - debug_error ("ERROR : audioconvert create error\n"); - goto ERROR; - } - - player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV; - player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv; - - /* caps filter */ - if (srcpad) - { - gst_object_unref (GST_OBJECT(srcpad)); - srcpad = NULL; - } - srcpad = gst_element_get_static_pad (conv, "src"); - - if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) - { - debug_error ("ERROR : capsfilter create error\n"); - goto ERROR; - } - - player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER; - player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter; - - caps = gst_caps_from_string( "audio/x-raw-int, " - "width = (int) 16, " - "depth = (int) 16, " - "channels = (int) 2"); - - g_object_set (GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL ); - gst_caps_unref( caps ); - - gst_element_set_state (conv, GST_STATE_PAUSED); - gst_element_set_state (filter, GST_STATE_PAUSED); - - /* deinterleave */ - if (srcpad) - { - gst_object_unref (GST_OBJECT(srcpad)); - srcpad = NULL; - } - srcpad = gst_element_get_static_pad (filter, "src"); - - if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) - { - debug_error ("ERROR : deinterleave create error\n"); - goto ERROR; - } - - g_object_set (deinterleave, "keep-positions", TRUE, NULL); - - MMPLAYER_SIGNAL_CONNECT (player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", - G_CALLBACK (__mmplayer_gst_deinterleave_pad_added), player); - - MMPLAYER_SIGNAL_CONNECT (player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", - G_CALLBACK (__mmplayer_gst_deinterleave_no_more_pads), player); - - player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE; - player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave; - - /* selector */ - selector = gst_element_factory_make ("input-selector", "audio-channel-selector"); - if (selector == NULL) - { - debug_error ("ERROR : audio-selector create error\n"); - goto ERROR; - } - - g_object_set (selector, "sync-streams", TRUE, NULL); - gst_bin_add (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector); - - player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR; - player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector; - - selector_srcpad = gst_element_get_static_pad (selector, "src"); - - debug_log ("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad)); - block_id = - gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, - __mmplayer_gst_selector_blocked, NULL, NULL); - - if (srcpad) - { - gst_object_unref (GST_OBJECT(srcpad)); - srcpad = NULL; - } - - srcpad = gst_element_get_static_pad(stereo_queue, "src"); - sinkpad = gst_element_get_request_pad (selector, "sink_%u"); - - if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) - { - debug_warning ("failed to link queue_stereo - selector\n"); - goto ERROR; - } - - player->audio_mode.total_track_num++; - - g_object_set (selector, "active-pad", sinkpad, NULL); - gst_element_set_state (deinterleave, GST_STATE_PAUSED); - gst_element_set_state (selector, GST_STATE_PAUSED); - - __mmplayer_gst_decode_callback (selector, selector_srcpad, player); - -ERROR: - - debug_log ("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad)); - if (block_id != 0) - { - gst_pad_remove_probe (selector_srcpad, block_id); - block_id = 0; - } - - if (sinkpad) - { - gst_object_unref (GST_OBJECT(sinkpad)); - sinkpad = NULL; - } - - if (srcpad) - { - gst_object_unref (GST_OBJECT(srcpad)); - srcpad = NULL; - } - - if (selector_srcpad) - { - gst_object_unref (GST_OBJECT(selector_srcpad)); - selector_srcpad = NULL; - } - - MMPLAYER_FLEAVE(); - return; -} - -static void -__mmplayer_gst_decode_no_more_pads (GstElement *elem, gpointer data) -{ - mm_player_t* player = NULL; - GstPad* srcpad = NULL; - GstElement* audio_selector = NULL; - GstElement* text_selector = NULL; - MMHandleType attrs = 0; - gint active_index = 0; - gint64 dur_bytes = 0L; - - player = (mm_player_t*) data; - - debug_log("no-more-pad signal handling\n"); - - if ((player->cmd == MMPLAYER_COMMAND_DESTROY) || - (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) - { - debug_warning("no need to go more"); - - if (player->gapless.reconfigure) - { - player->gapless.reconfigure = FALSE; - MMPLAYER_PLAYBACK_UNLOCK(player); - } - - return; - } - - if ((!MMPLAYER_IS_HTTP_PD(player)) && - (MMPLAYER_IS_HTTP_STREAMING(player)) && - (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) && - (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) - { - #define ESTIMATED_BUFFER_UNIT (1*1024*1024) - - if (NULL == player->streamer) - { - debug_warning("invalid state for buffering"); - goto ERROR; - } - - gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second; - guint buffer_bytes = init_buffering_time * ESTIMATED_BUFFER_UNIT; - - buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes); - debug_log("[Decodebin2] set use-buffering on Q2 (pre buffer time: %d sec, buffer size : %d)\n", (gint)init_buffering_time, buffer_bytes); - - init_buffering_time = (init_buffering_time != 0)?(init_buffering_time):(player->ini.http_buffering_time); - - if ( !gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes)) - debug_error("fail to get duration.\n"); - - // enable use-buffering on queue2 instead of multiqueue (ex)audio only streaming - // use file information was already set on Q2 when it was created. - __mm_player_streaming_set_queue2(player->streamer, - player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, - TRUE, // use_buffering - buffer_bytes, - init_buffering_time, - 1.0, // low percent - player->ini.http_buffering_limit, // high percent - FALSE, - NULL, - ((dur_bytes>0)?((guint64)dur_bytes):0)); - } - audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst; - text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst; - if (audio_selector) - { - active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index; - if ((active_index != DEFAULT_TRACK) && - (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) - { - debug_warning("failed to change audio track\n"); - player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK; - } - - // [link] input-selector :: audiobin - srcpad = gst_element_get_static_pad (audio_selector, "src"); - if (!srcpad) - { - debug_error("failed to get srcpad from selector\n"); - goto ERROR; - } - - debug_log ("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad)); - if (!text_selector) - player->no_more_pad = TRUE; - - if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) - { - debug_log ("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad)); - if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) - { - gst_pad_remove_probe (srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id); - player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0; - } - - __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player); - } - else - { - __mmplayer_gst_decode_callback (audio_selector, srcpad, player); - - debug_log ("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad)); - if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) - { - gst_pad_remove_probe (srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id); - player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0; - } - } - - debug_log("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num); - - attrs = MMPLAYER_GET_ATTRS(player); - if ( attrs ) - { - mm_attrs_set_int_by_name(attrs, "content_audio_track_num",(gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num); - if (mmf_attrs_commit (attrs)) - debug_error("failed to commit.\n"); - } - else - { - debug_error("cannot get content attribute"); - } - } - else - { - if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) - { - debug_log ("There is no audio track : remove audiobin"); - - __mmplayer_release_signal_connection( player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN ); - __mmplayer_del_sink ( player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst ); - - MMPLAYER_RELEASE_ELEMENT ( player, player->pipeline->audiobin, MMPLAYER_A_BIN ); - MMPLAYER_FREEIF ( player->pipeline->audiobin ) - } - - if (player->num_dynamic_pad == 0) - { - __mmplayer_pipeline_complete (NULL, player); - } - } - - - if (!MMPLAYER_IS_ES_BUFF_SRC(player)) - { - if (text_selector) - { - __mmplayer_handle_text_decode_path(player, text_selector); - } - } - - MMPLAYER_FLEAVE(); - -ERROR: - if (srcpad) - { - gst_object_unref ( GST_OBJECT(srcpad) ); - srcpad = NULL; - } - - if (player->gapless.reconfigure) - { - player->gapless.reconfigure = FALSE; - MMPLAYER_PLAYBACK_UNLOCK(player); - } -} - -static void -__mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data) // @ -{ - mm_player_t* player = NULL; - MMHandleType attrs = 0; - GstElement* pipeline = NULL; - GstCaps* caps = NULL; - gchar* caps_str = NULL; - GstStructure* str = NULL; - const gchar* name = NULL; - GstPad* sinkpad = NULL; - GstElement* sinkbin = NULL; - gboolean reusing = FALSE; - GstElement *text_selector = NULL; - - /* check handles */ - player = (mm_player_t*) data; - - return_if_fail( elem && pad ); - return_if_fail(player && player->pipeline && player->pipeline->mainbin); - - pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst; - - attrs = MMPLAYER_GET_ATTRS(player); - if ( !attrs ) - { - debug_error("cannot get content attribute\n"); - goto ERROR; - } - - /* get mimetype from caps */ - caps = gst_pad_query_caps( pad, NULL ); - if ( !caps ) - { - debug_error("cannot get caps from pad.\n"); - goto ERROR; - } - caps_str = gst_caps_to_string(caps); - - str = gst_caps_get_structure( caps, 0 ); - if ( ! str ) - { - debug_error("cannot get structure from caps.\n"); - goto ERROR; - } - - name = gst_structure_get_name(str); - if ( ! name ) - { - debug_error("cannot get mimetype from structure.\n"); - goto ERROR; - } - - //debug_log("detected mimetype : %s\n", name); - - if (strstr(name, "audio")) - { - if (player->pipeline->audiobin == NULL) - { - if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) - { - debug_error("failed to create audiobin. continuing without audio\n"); - goto ERROR; - } - - sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst; - debug_log("creating audiosink bin success\n"); - } - else - { - reusing = TRUE; - sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst; - debug_log("reusing audiobin\n"); - _mmplayer_update_content_attrs( player, ATTR_AUDIO); - } - - if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks - mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1); - - player->audiosink_linked = 1; - - sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "sink" ); - if ( !sinkpad ) - { - debug_error("failed to get pad from sinkbin\n"); - goto ERROR; - } - } - else if (strstr(name, "video")) - { - if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12")) - { - player->set_mode.video_zc = TRUE; - } - - if (player->pipeline->videobin == NULL) - { - /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */ - /* get video surface type */ - int surface_type = 0; - mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type); - - if (surface_type == MM_DISPLAY_SURFACE_NULL) - { - debug_log("not make videobin because it dose not want\n"); - goto ERROR; - } - - if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type) ) - { - debug_error("failed to create videobin. continuing without video\n"); - goto ERROR; - } - - sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst; - debug_log("creating videosink bin success\n"); - } - else - { - reusing = TRUE; - sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst; - debug_log("re-using videobin\n"); - _mmplayer_update_content_attrs( player, ATTR_VIDEO); - } - - /* FIXIT : track number shouldn't be hardcoded */ - mm_attrs_set_int_by_name(attrs, "content_video_track_num", 1); - player->videosink_linked = 1; - - /* NOTE : intermediate code before doing H/W subtitle compositon */ - if ( player->use_textoverlay && player->play_subtitle ) - { - debug_log("using textoverlay for external subtitle"); - /* check text bin has created well */ - if ( player->pipeline && player->pipeline->textbin ) - { - /* get sinkpad from textoverlay */ - sinkpad = gst_element_get_static_pad( - GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst), - "video_sink" ); - if ( ! sinkpad ) - { - debug_error("failed to get sink pad from textoverlay"); - goto ERROR; - } - - /* link new pad with textoverlay first */ - if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) ) - { - debug_error("failed to get pad from sinkbin\n"); - goto ERROR; - } - - gst_object_unref(sinkpad); - sinkpad = NULL; - - /* alright, override pad to textbin.src for futher link */ - pad = gst_element_get_static_pad( - GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst), - "src" ); - if ( ! pad ) - { - debug_error("failed to get sink pad from textoverlay"); - goto ERROR; - } - } - else - { - debug_error("should not reach here."); - goto ERROR; - } - } - - sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "sink" ); - if ( !sinkpad ) - { - debug_error("failed to get pad from sinkbin\n"); - goto ERROR; - } - } - else if (strstr(name, "text")) - { - if (player->pipeline->textbin == NULL) - { - MMPlayerGstElement* mainbin = NULL; - - if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) - { - debug_error("failed to create textbin. continuing without text\n"); - goto ERROR; - } - - sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst; - debug_log("creating textsink bin success\n"); - - /* FIXIT : track number shouldn't be hardcoded */ - mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1); - - player->textsink_linked = 1; - debug_msg("player->textsink_linked set to 1\n"); - - sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "text_sink" ); - if ( !sinkpad ) - { - debug_error("failed to get pad from sinkbin\n"); - goto ERROR; - } - - mainbin = player->pipeline->mainbin; - - if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) - { - /* input selector */ - text_selector = gst_element_factory_make("input-selector", "subtitle_inselector"); - if ( !text_selector ) - { - debug_error ( "failed to create subtitle input selector element\n" ); - goto ERROR; - } - g_object_set (text_selector, "sync-streams", TRUE, NULL); - - mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR; - mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector; - - /* warm up */ - if (GST_STATE_CHANGE_FAILURE == gst_element_set_state (text_selector, GST_STATE_READY)) - { - debug_error("failed to set state(READY) to sinkbin\n"); - goto ERROR; - } - - if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) - { - debug_warning("failed to add subtitle input selector\n"); - goto ERROR; - } - - debug_log ("created element input-selector"); - - } - else - { - debug_log ("already having subtitle input selector"); - text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst; - } - } - - else - { - if (!player->textsink_linked) - { - debug_log("re-using textbin\n"); - - reusing = TRUE; - sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst; - - player->textsink_linked = 1; - debug_msg("player->textsink_linked set to 1\n"); - } - else - { - debug_log("ignoring internal subtutle since external subtitle is available"); - } - } - } - else - { - debug_warning("unknown type of elementary stream! ignoring it...\n"); - goto ERROR; - } - - if ( sinkbin ) - { - if(!reusing) - { - /* warm up */ - if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state( sinkbin, GST_STATE_READY ) ) - { - debug_error("failed to set state(READY) to sinkbin\n"); - goto ERROR; - } - - /* Added for multi audio support to avoid adding audio bin again*/ - /* add */ - if ( FALSE == gst_bin_add( GST_BIN(pipeline), sinkbin ) ) - { - debug_error("failed to add sinkbin to pipeline\n"); - goto ERROR; - } - } - - /* link */ - if (GST_PAD_LINK_OK != GST_PAD_LINK (pad, sinkpad)) - { - debug_error("failed to get pad from sinkbin\n"); - goto ERROR; - } - - if (!reusing) - { - /* run */ - if (GST_STATE_CHANGE_FAILURE == gst_element_set_state (sinkbin, GST_STATE_PAUSED)) - { - debug_error("failed to set state(PAUSED) to sinkbin\n"); - goto ERROR; - } - - if (text_selector) - { - if (GST_STATE_CHANGE_FAILURE == gst_element_set_state (text_selector, GST_STATE_PAUSED)) - { - debug_error("failed to set state(PAUSED) to sinkbin\n"); - goto ERROR; - } - } - } - - gst_object_unref (sinkpad); - sinkpad = NULL; - } - - debug_log ("linking sink bin success\n"); - - /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in - * streaming task. if the task blocked, then buffer will not flow to the next element - * ( autoplugging element ). so this is special hack for streaming. please try to remove it - */ - /* dec stream count. we can remove fakesink if it's zero */ - if (player->num_dynamic_pad) - player->num_dynamic_pad--; - - debug_log ("no more pads: %d stream count dec : %d (num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad); - - if ((player->no_more_pad) && (player->num_dynamic_pad == 0)) - { - __mmplayer_pipeline_complete (NULL, player); - } - - /* FIXIT : please leave a note why this code is needed */ - if(MMPLAYER_IS_WFD_STREAMING( player )) - { - player->no_more_pad = TRUE; - } - -ERROR: - - MMPLAYER_FREEIF(caps_str); - - if ( caps ) - gst_caps_unref( caps ); - - if ( sinkpad ) - gst_object_unref(GST_OBJECT(sinkpad)); - - /* flusing out new attributes */ - if ( mmf_attrs_commit ( attrs ) ) - { - debug_error("failed to comit attributes\n"); - } - - return; -} - -static gboolean -__mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value) -{ - int pro_value = 0; // in the case of expection, default will be returned. - int dest_angle = rotation_angle; - int rotation_type = -1; - #define ROTATION_USING_SINK 0 - #define ROTATION_USING_CUSTOM 1 - #define ROTATION_USING_FLIP 2 - - return_val_if_fail(player, FALSE); - return_val_if_fail(value, FALSE); - return_val_if_fail(rotation_angle >= 0, FALSE); - - if (rotation_angle >= 360) - { - dest_angle = rotation_angle - 360; - } - - /* chech if supported or not */ - if ( dest_angle % 90 ) - { - debug_log("not supported rotation angle = %d", rotation_angle); - return FALSE; - } - - /* - * xvimagesink only (A) - * custom_convert - no xv (e.g. memsink, evasimagesink (B) - * videoflip - avsysmemsink (C) - */ - if (player->set_mode.video_zc) - { - if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B - { - rotation_type = ROTATION_USING_CUSTOM; - } - else // A - { - rotation_type = ROTATION_USING_SINK; - } - } - else - { - int surface_type = 0; - rotation_type = ROTATION_USING_FLIP; - - mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type); - debug_log("check display surface type attribute: %d", surface_type); - - if ((surface_type == MM_DISPLAY_SURFACE_X) || - (surface_type == MM_DISPLAY_SURFACE_EVAS && !strcmp(player->ini.videosink_element_evas, "evaspixmapsink"))) - { - rotation_type = ROTATION_USING_SINK; - } - else - { - rotation_type = ROTATION_USING_FLIP; //C - } - - debug_log("using %d type for rotation", rotation_type); - } - - /* get property value for setting */ - switch(rotation_type) - { - case ROTATION_USING_SINK: // xvimagesink, pixmap - { - switch (dest_angle) - { - case 0: - break; - case 90: - pro_value = 3; // clockwise 90 - break; - case 180: - pro_value = 2; - break; - case 270: - pro_value = 1; // counter-clockwise 90 - break; - } - } - break; - case ROTATION_USING_CUSTOM: - { - gchar *ename = NULL; - ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst)); - - if (g_strrstr(ename, "fimcconvert")) - { - switch (dest_angle) - { - case 0: - break; - case 90: - pro_value = 90; // clockwise 90 - break; - case 180: - pro_value = 180; - break; - case 270: - pro_value = 270; // counter-clockwise 90 - break; - } - } - } - break; - case ROTATION_USING_FLIP: // videoflip - { - switch (dest_angle) - { - - case 0: - break; - case 90: - pro_value = 1; // clockwise 90 - break; - case 180: - pro_value = 2; - break; - case 270: - pro_value = 3; // counter-clockwise 90 - break; - } - } - break; - } - - debug_log("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type); - - *value = pro_value; - - return TRUE; -} - -int -_mmplayer_update_video_param(mm_player_t* player) // @ -{ - MMHandleType attrs = 0; - int surface_type = 0; - int org_angle = 0; // current supported angle values are 0, 90, 180, 270 - int user_angle = 0; - int user_angle_type= 0; - int rotation_value = 0; - gchar *org_orient = NULL; - - MMPLAYER_FENTER(); - - /* check video sinkbin is created */ - return_val_if_fail ( player && - player->pipeline && - player->pipeline->videobin && - player->pipeline->videobin[MMPLAYER_V_BIN].gst && - player->pipeline->videobin[MMPLAYER_V_SINK].gst, - MM_ERROR_PLAYER_NOT_INITIALIZED ); - - attrs = MMPLAYER_GET_ATTRS(player); - if ( !attrs ) - { - debug_error("cannot get content attribute"); - return MM_ERROR_PLAYER_INTERNAL; - } - - /* update user roation */ - mm_attrs_get_int_by_name(attrs, "display_rotation", &user_angle_type); - - /* get angle with user type */ - switch(user_angle_type) - { - case MM_DISPLAY_ROTATION_NONE: - user_angle = 0; - break; - case MM_DISPLAY_ROTATION_90: // counter-clockwise 90 - user_angle = 270; - break; - case MM_DISPLAY_ROTATION_180: - user_angle = 180; - break; - case MM_DISPLAY_ROTATION_270: // clockwise 90 - user_angle = 90; - break; - } - - /* get original orientation */ - mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient); - - if (org_orient) - { - if (!strcmp (org_orient, "rotate-90")) - org_angle = 90; - else if (!strcmp (org_orient, "rotate-180")) - org_angle = 180; - else if (!strcmp (org_orient, "rotate-270")) - org_angle = 270; - else - debug_log ("original rotation is %s", org_orient); - } - else - { - debug_log ("content_video_orientation get fail"); - } - - debug_log("check user angle: %d, orientation: %d", user_angle, org_angle); - - /* check video stream callback is used */ - if(!player->set_mode.media_packet_video_stream && player->use_video_stream ) - { - if (player->set_mode.video_zc) - { - gchar *ename = NULL; - int width = 0; - int height = 0; - - mm_attrs_get_int_by_name(attrs, "display_width", &width); - mm_attrs_get_int_by_name(attrs, "display_height", &height); - - /* resize video frame with requested values for fimcconvert */ - ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst)); - - if (ename && g_strrstr(ename, "fimcconvert")) - { - if (width) - g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-width", width, NULL); - - if (height) - g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-height", height, NULL); - - /* NOTE: fimcconvert does not manage index of src buffer from upstream src-plugin, decoder gives frame information in output buffer with no ordering */ - g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "src-rand-idx", TRUE, NULL); - - /* get rotation value to set */ - __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value); - - g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "rotate", rotation_value, NULL); - - debug_log("updating fimcconvert - r[%d], w[%d], h[%d]", rotation_value, width, height); - } - } - else - { - debug_log("using video stream callback with memsink. player handle : [%p]", player); - - /* get rotation value to set */ - __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value); - - g_object_set(player->pipeline->videobin[MMPLAYER_V_FLIP].gst, "method", rotation_value, NULL); - } - - return MM_ERROR_NONE; - } - - /* update display surface */ - mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type); - debug_log("check display surface type attribute: %d", surface_type); - - /* configuring display */ - switch ( surface_type ) - { - case MM_DISPLAY_SURFACE_X: - { - /* ximagesink or xvimagesink */ - void *surface = NULL; - int display_method = 0; - int roi_x = 0; - int roi_y = 0; - int roi_w = 0; - int roi_h = 0; - int src_crop_x = 0; - int src_crop_y = 0; - int src_crop_w = 0; - int src_crop_h = 0; - int force_aspect_ratio = 0; - gboolean visible = TRUE; - -#ifdef HAVE_WAYLAND - /*set wl_display*/ - void* wl_display = NULL; - GstContext *context = NULL; - int wl_window_x = 0; - int wl_window_y = 0; - int wl_window_width = 0; - int wl_window_height = 0; - - mm_attrs_get_data_by_name(attrs, "wl_display", &wl_display); - if (wl_display) - context = gst_wayland_display_handle_context_new(wl_display); - if (context) - gst_element_set_context(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), context); - - /*It should be set after setting window*/ - mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x); - mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y); - mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width); - mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height); -#endif - /* common case if using x surface */ - mm_attrs_get_data_by_name(attrs, "display_overlay", &surface); - if ( surface ) - { -#ifdef HAVE_WAYLAND - guintptr wl_surface = (guintptr)surface; - debug_log("set video param : wayland surface %p", surface); - gst_video_overlay_set_window_handle( - GST_VIDEO_OVERLAY( player->pipeline->videobin[MMPLAYER_V_SINK].gst ), - wl_surface ); - /* After setting window handle, set render rectangle */ - gst_video_overlay_set_render_rectangle( - GST_VIDEO_OVERLAY( player->pipeline->videobin[MMPLAYER_V_SINK].gst ), - wl_window_x,wl_window_y,wl_window_width,wl_window_height); -#else // HAVE_X11 - int xwin_id = 0; - xwin_id = *(int*)surface; - debug_log("set video param : xid %p", *(int*)surface); - if (xwin_id) - { - gst_video_overlay_set_window_handle( GST_VIDEO_OVERLAY( player->pipeline->videobin[MMPLAYER_V_SINK].gst ), *(int*)surface ); - } -#endif - } - else - { - /* FIXIT : is it error case? */ - debug_warning("still we don't have xid on player attribute. create it's own surface."); - } - - /* if xvimagesink */ - if (!strcmp(player->ini.videosink_element_x,"xvimagesink")) - { - mm_attrs_get_int_by_name(attrs, "display_force_aspect_ration", &force_aspect_ratio); - mm_attrs_get_int_by_name(attrs, "display_method", &display_method); - mm_attrs_get_int_by_name(attrs, "display_src_crop_x", &src_crop_x); - mm_attrs_get_int_by_name(attrs, "display_src_crop_y", &src_crop_y); - mm_attrs_get_int_by_name(attrs, "display_src_crop_width", &src_crop_w); - mm_attrs_get_int_by_name(attrs, "display_src_crop_height", &src_crop_h); - mm_attrs_get_int_by_name(attrs, "display_roi_x", &roi_x); - mm_attrs_get_int_by_name(attrs, "display_roi_y", &roi_y); - mm_attrs_get_int_by_name(attrs, "display_roi_width", &roi_w); - mm_attrs_get_int_by_name(attrs, "display_roi_height", &roi_h); - mm_attrs_get_int_by_name(attrs, "display_visible", &visible); - #define DEFAULT_DISPLAY_MODE 2 // TV only, PRI_VIDEO_OFF_AND_SEC_VIDEO_FULL_SCREEN - - /* setting for cropping media source */ - if (src_crop_w && src_crop_h) - { - g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, - "src-crop-x", src_crop_x, - "src-crop-y", src_crop_y, - "src-crop-w", src_crop_w, - "src-crop-h", src_crop_h, - NULL ); - } - - /* setting for ROI mode */ - if (display_method == 5) // 5 for ROI mode - { - int roi_mode = 0; - mm_attrs_get_int_by_name(attrs, "display_roi_mode", &roi_mode); - g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, - "dst-roi-mode", roi_mode, - "dst-roi-x", roi_x, - "dst-roi-y", roi_y, - "dst-roi-w", roi_w, - "dst-roi-h", roi_h, - NULL ); - /* get rotation value to set, - do not use org_angle because ROI mode in xvimagesink needs both a rotation value and an orientation value */ - __mmplayer_get_property_value_for_rotation(player, user_angle, &rotation_value); - } - else - { - /* get rotation value to set */ - __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value); - } - - g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, - "force-aspect-ratio", force_aspect_ratio, - "orientation", org_angle/90, // setting for orientation of media, it is used for ROI/ZOOM feature in xvimagesink - "rotate", rotation_value, - "handle-events", TRUE, - "display-geometry-method", display_method, - "draw-borders", FALSE, - "handle-expose", FALSE, - "visible", visible, - "display-mode", DEFAULT_DISPLAY_MODE, - NULL ); - - debug_log("set video param : rotate %d, method %d visible %d", rotation_value, display_method, visible); - debug_log("set video param : dst-roi-x: %d, dst-roi-y: %d, dst-roi-w: %d, dst-roi-h: %d", roi_x, roi_y, roi_w, roi_h ); - debug_log("set video param : force aspect ratio %d, display mode %d", force_aspect_ratio, DEFAULT_DISPLAY_MODE); - } - } - break; - case MM_DISPLAY_SURFACE_EVAS: - { - void *object = NULL; - int scaling = 0; - gboolean visible = TRUE; - int display_method = 0; - - /* common case if using evas surface */ - mm_attrs_get_data_by_name(attrs, "display_overlay", &object); - mm_attrs_get_int_by_name(attrs, "display_visible", &visible); - mm_attrs_get_int_by_name(attrs, "display_evas_do_scaling", &scaling); - mm_attrs_get_int_by_name(attrs, "display_method", &display_method); - - /* if evasimagesink */ - if (!strcmp(player->ini.videosink_element_evas,"evasimagesink")) - { - if (object) - { - /* if it is evasimagesink, we are not supporting rotation */ - if (user_angle_type!=MM_DISPLAY_ROTATION_NONE) - { - mm_attrs_set_int_by_name(attrs, "display_rotation", MM_DISPLAY_ROTATION_NONE); - if (mmf_attrs_commit (attrs)) /* return -1 if error */ - debug_error("failed to commit\n"); - debug_warning("unsupported feature"); - return MM_ERROR_NOT_SUPPORT_API; - } - __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value); - g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, - "evas-object", object, - "visible", visible, - "display-geometry-method", display_method, - "rotate", rotation_value, - NULL); - debug_log("set video param : method %d", display_method); - debug_log("set video param : evas-object %x, visible %d", object, visible); - debug_log("set video param : evas-object %x, rotate %d", object, rotation_value); - } - else - { - debug_error("no evas object"); - return MM_ERROR_PLAYER_INTERNAL; - } - - - /* if evasimagesink using converter */ - if (player->set_mode.video_zc && player->pipeline->videobin[MMPLAYER_V_CONV].gst) - { - int width = 0; - int height = 0; - int no_scaling = !scaling; - - mm_attrs_get_int_by_name(attrs, "display_width", &width); - mm_attrs_get_int_by_name(attrs, "display_height", &height); - - /* NOTE: fimcconvert does not manage index of src buffer from upstream src-plugin, decoder gives frame information in output buffer with no ordering */ - g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "src-rand-idx", TRUE, NULL); - g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-buffer-num", 5, NULL); - - if (no_scaling) - { - /* no-scaling order to fimcconvert, original width, height size of media src will be passed to sink plugin */ - g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, - "dst-width", 0, /* setting 0, output video width will be media src's width */ - "dst-height", 0, /* setting 0, output video height will be media src's height */ - NULL); - } - else - { - /* scaling order to fimcconvert */ - if (width) - { - g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-width", width, NULL); - } - if (height) - { - g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-height", height, NULL); - } - debug_log("set video param : video frame scaling down to width(%d) height(%d)", width, height); - } - debug_log("set video param : display_evas_do_scaling %d", scaling); - } - } - - /* if evaspixmapsink */ - if (!strcmp(player->ini.videosink_element_evas,"evaspixmapsink")) - { - if (object) - { - __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value); - g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, - "evas-object", object, - "visible", visible, - "display-geometry-method", display_method, - "rotate", rotation_value, - NULL); - debug_log("set video param : method %d", display_method); - debug_log("set video param : evas-object %x, visible %d", object, visible); - debug_log("set video param : evas-object %x, rotate %d", object, rotation_value); - } - else - { - debug_error("no evas object"); - return MM_ERROR_PLAYER_INTERNAL; - } - - int display_method = 0; - int roi_x = 0; - int roi_y = 0; - int roi_w = 0; - int roi_h = 0; - int origin_size = !scaling; - - mm_attrs_get_int_by_name(attrs, "display_method", &display_method); - mm_attrs_get_int_by_name(attrs, "display_roi_x", &roi_x); - mm_attrs_get_int_by_name(attrs, "display_roi_y", &roi_y); - mm_attrs_get_int_by_name(attrs, "display_roi_width", &roi_w); - mm_attrs_get_int_by_name(attrs, "display_roi_height", &roi_h); - - /* get rotation value to set */ - __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value); - - g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, - "origin-size", origin_size, - "rotate", rotation_value, - "dst-roi-x", roi_x, - "dst-roi-y", roi_y, - "dst-roi-w", roi_w, - "dst-roi-h", roi_h, - "display-geometry-method", display_method, - NULL ); - - debug_log("set video param : method %d", display_method); - debug_log("set video param : dst-roi-x: %d, dst-roi-y: %d, dst-roi-w: %d, dst-roi-h: %d", - roi_x, roi_y, roi_w, roi_h ); - debug_log("set video param : display_evas_do_scaling %d (origin-size %d)", scaling, origin_size); - } - } - break; - case MM_DISPLAY_SURFACE_X_EXT: /* NOTE : this surface type is used for the videoTexture(canvasTexture) overlay */ - { - void *pixmap_id_cb = NULL; - void *pixmap_id_cb_user_data = NULL; - int display_method = 0; - gboolean visible = TRUE; - - /* if xvimagesink */ - if (strcmp(player->ini.videosink_element_x,"xvimagesink")) - { - debug_error("videosink is not xvimagesink"); - return MM_ERROR_PLAYER_INTERNAL; - } - - /* get information from attributes */ - mm_attrs_get_data_by_name(attrs, "display_overlay", &pixmap_id_cb); - mm_attrs_get_data_by_name(attrs, "display_overlay_user_data", &pixmap_id_cb_user_data); - mm_attrs_get_int_by_name(attrs, "display_method", &display_method); - mm_attrs_get_int_by_name(attrs, "display_visible", &visible); - - if ( pixmap_id_cb ) - { - debug_log("set video param : display_overlay(0x%x)", pixmap_id_cb); - if (pixmap_id_cb_user_data) - { - debug_log("set video param : display_overlay_user_data(0x%x)", pixmap_id_cb_user_data); - } - } - else - { - debug_error("failed to set pixmap-id-callback"); - return MM_ERROR_PLAYER_INTERNAL; - } - /* get rotation value to set */ - __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value); - - debug_log("set video param : rotate %d, method %d, visible %d", rotation_value, display_method, visible); - - /* set properties of videosink plugin */ - g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, - "display-geometry-method", display_method, - "draw-borders", FALSE, - "visible", visible, - "rotate", rotation_value, - "pixmap-id-callback", pixmap_id_cb, - "pixmap-id-callback-userdata", pixmap_id_cb_user_data, - NULL ); - } - break; - case MM_DISPLAY_SURFACE_NULL: - { - /* do nothing */ - } - break; - case MM_DISPLAY_SURFACE_REMOTE: - { - /* do nothing */ - } - break; - } - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -static int -__mmplayer_gst_element_link_bucket(GList* element_bucket) // @ -{ - GList* bucket = element_bucket; - MMPlayerGstElement* element = NULL; - MMPlayerGstElement* prv_element = NULL; - gint successful_link_count = 0; - - MMPLAYER_FENTER(); - - return_val_if_fail(element_bucket, -1); - - prv_element = (MMPlayerGstElement*)bucket->data; - bucket = bucket->next; - - for ( ; bucket; bucket = bucket->next ) - { - element = (MMPlayerGstElement*)bucket->data; - - if ( element && element->gst ) - { - /* If next element is audio appsrc then make a seprate audio pipeline */ - if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),"audio_appsrc") || - !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),"subtitle_appsrc")) - { - prv_element = element; - continue; - } - - if ( GST_ELEMENT_LINK(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst)) ) - { - debug_log("linking [%s] to [%s] success\n", - GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)), - GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) ); - successful_link_count ++; - } - else - { - debug_log("linking [%s] to [%s] failed\n", - GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)), - GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) ); - return -1; - } - } - - prv_element = element; - } - - MMPLAYER_FLEAVE(); - - return successful_link_count; -} - -static int -__mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket) // @ -{ - GList* bucket = element_bucket; - MMPlayerGstElement* element = NULL; - int successful_add_count = 0; - - MMPLAYER_FENTER(); - - return_val_if_fail(element_bucket, 0); - return_val_if_fail(bin, 0); - - for ( ; bucket; bucket = bucket->next ) - { - element = (MMPlayerGstElement*)bucket->data; - - if ( element && element->gst ) - { - if( !gst_bin_add(bin, GST_ELEMENT(element->gst)) ) - { - debug_log("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n", - GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), - GST_ELEMENT_NAME(GST_ELEMENT(bin) ) ); - return 0; - } - successful_add_count ++; - } - } - - MMPLAYER_FLEAVE(); - - return successful_add_count; -} - -static void __mmplayer_gst_caps_notify_cb (GstPad * pad, GParamSpec * unused, gpointer data) -{ - mm_player_t* player = (mm_player_t*) data; - GstCaps *caps = NULL; - GstStructure *str = NULL; - const char *name; - - MMPLAYER_FENTER(); - - return_if_fail ( pad ) - return_if_fail ( unused ) - return_if_fail ( data ) - - caps = gst_pad_query_caps(pad, NULL); - if ( !caps ) - { - return; - } - - str = gst_caps_get_structure(caps, 0); - if ( !str ) - { - goto ERROR; - } - - name = gst_structure_get_name(str); - if ( !name ) - { - goto ERROR; - } - - debug_log("name = %s\n", name); - - if (strstr(name, "audio")) - { - _mmplayer_update_content_attrs (player, ATTR_AUDIO); - - if (player->audio_stream_changed_cb) - { - debug_error("call the audio stream changed cb\n"); - player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param); - } - } - else if (strstr(name, "video")) - { - _mmplayer_update_content_attrs (player, ATTR_VIDEO); - - if (player->video_stream_changed_cb) - { - debug_error("call the video stream changed cb\n"); - player->video_stream_changed_cb(player->video_stream_changed_cb_user_param); - } - } - else - { - goto ERROR; - } - -ERROR: - - gst_caps_unref(caps); - - MMPLAYER_FLEAVE(); - - return; -} - - - -/** - * This function is to create audio pipeline for playing. - * - * @param player [in] handle of player - * - * @return This function returns zero on success. - * @remark - * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline - */ -#define MMPLAYER_CREATEONLY_ELEMENT(x_bin, x_id, x_factory, x_name) \ -x_bin[x_id].id = x_id;\ -x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\ -if ( ! x_bin[x_id].gst )\ -{\ - debug_error("failed to create %s \n", x_factory);\ - goto ERROR;\ -}\ - -#define MMPLAYER_CREATE_ELEMENT_ADD_BIN(x_bin, x_id, x_factory, x_name, y_bin, x_player) \ -x_bin[x_id].id = x_id;\ -x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\ -if ( ! x_bin[x_id].gst )\ -{\ - debug_error("failed to create %s \n", x_factory);\ - goto ERROR;\ -}\ -else\ -{\ - if (x_player->ini.set_dump_element_flag)\ - __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\ -}\ -if( !gst_bin_add(GST_BIN(y_bin), GST_ELEMENT(x_bin[x_id].gst)))\ -{\ - debug_log("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",\ - GST_ELEMENT_NAME(GST_ELEMENT(x_bin[x_id].gst)),\ - GST_ELEMENT_NAME(GST_ELEMENT(y_bin) ) );\ - goto ERROR;\ -}\ - -/* macro for code readability. just for sinkbin-creation functions */ -#define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \ -do \ -{ \ - x_bin[x_id].id = x_id;\ - x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\ - if ( ! x_bin[x_id].gst )\ - {\ - debug_error("failed to create %s \n", x_factory);\ - goto ERROR;\ - }\ - else\ - {\ - if (x_player->ini.set_dump_element_flag)\ - __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\ - }\ - if ( x_add_bucket )\ - element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\ -} while(0); - -static void -__mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data) -{ - mm_player_t* player = (mm_player_t*) data; - - gint channel = 0; - gint rate = 0; - gint depth = 0; - gint endianness = 0; - guint64 channel_mask = 0; - - MMPlayerAudioStreamDataType audio_stream = { 0, }; - GstMapInfo mapinfo = GST_MAP_INFO_INIT; - - MMPLAYER_FENTER(); - return_if_fail(player->audio_stream_render_cb_ex); - - debug_log ("__mmplayer_audio_stream_decoded_render_cb new pad: %s", GST_PAD_NAME (pad)); - - gst_buffer_map(buffer, &mapinfo, GST_MAP_READ); - audio_stream.data = mapinfo.data; - audio_stream.data_size = mapinfo.size; - - GstCaps *caps = gst_pad_get_current_caps( pad ); - GstStructure *structure = gst_caps_get_structure (caps, 0); - - MMPLAYER_LOG_GST_CAPS_TYPE(caps); - gst_structure_get_int (structure, "rate", &rate); - gst_structure_get_int (structure, "channels", &channel); - gst_structure_get_int (structure, "depth", &depth); - gst_structure_get_int (structure, "endianness", &endianness); - gst_structure_get (structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL); - - gst_caps_unref(GST_CAPS(caps)); - - audio_stream.bitrate = rate; - audio_stream.channel = channel; - audio_stream.depth = depth; - audio_stream.is_little_endian = (endianness == 1234 ? 1 : 0); - audio_stream.channel_mask = channel_mask; - debug_log ("bitrate : %d channel : %d depth: %d ls_little_endian : %d channel_mask: %d, %p", rate, channel, depth, endianness, channel_mask, player->audio_stream_cb_user_param); - player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param); - gst_buffer_unmap(buffer, &mapinfo); - - MMPLAYER_FLEAVE(); -} - -static void -__mmplayer_gst_audio_deinterleave_pad_added (GstElement *elem, GstPad *pad, gpointer data) -{ - mm_player_t* player = (mm_player_t*)data; - MMPlayerGstElement* audiobin = player->pipeline->audiobin; - GstPad* sinkpad = NULL; - GstElement *queue = NULL, *sink = NULL; - - MMPLAYER_FENTER(); - return_if_fail (player && player->pipeline && player->pipeline->mainbin); - - queue = gst_element_factory_make ("queue", NULL); - if (queue == NULL) - { - debug_log ("fail make queue\n"); - goto ERROR; - } - - sink = gst_element_factory_make ("fakesink", NULL); - if (sink == NULL) - { - debug_log ("fail make fakesink\n"); - goto ERROR; - } - - gst_bin_add_many (GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL); - - if (!gst_element_link_pads_full (queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) - { - debug_warning("failed to link queue & sink\n"); - goto ERROR; - } - - sinkpad = gst_element_get_static_pad (queue, "sink"); - - if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) - { - debug_warning ("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad)); - goto ERROR; - } - - debug_error("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync); - - gst_object_unref (sinkpad); - g_object_set (sink, "sync", player->audio_stream_sink_sync, NULL); - g_object_set (sink, "signal-handoffs", TRUE, NULL); - - gst_element_set_state (sink, GST_STATE_PAUSED); - gst_element_set_state (queue, GST_STATE_PAUSED); - - MMPLAYER_SIGNAL_CONNECT( player, - G_OBJECT(sink), - MM_PLAYER_SIGNAL_TYPE_AUDIOBIN, - "handoff", - G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb), - (gpointer)player ); - - MMPLAYER_FLEAVE(); - return ; - -ERROR: - debug_error("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n"); - if (queue) - { - gst_object_unref(GST_OBJECT(queue)); - queue = NULL; - } - if (sink) - { - gst_object_unref(GST_OBJECT(sink)); - sink = NULL; - } - if (sinkpad) - { - gst_object_unref ( GST_OBJECT(sinkpad) ); - sinkpad = NULL; - } - - return; -} - -void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs) -{ - #define MAX_PROPS_LEN 64 - gint volume_type = 0; - gint latency_mode = 0; - gchar *stream_type = NULL; - gchar *latency = NULL; - gint stream_id = 0; - gchar stream_props[MAX_PROPS_LEN] = {0,}; - GstStructure *props = NULL; - - /* set volume table - * It should be set after player creation through attribute. - * But, it can not be changed during playing. - */ - MMPLAYER_FENTER(); - mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id); - mm_attrs_get_string_by_name (attrs, "sound_stream_type", &stream_type ); - - if ( stream_id < 1 || !stream_type || strlen(stream_type) < 1) - { - debug_error("stream_id[%d] or stream_type[%s] is not valid.\n", stream_id, stream_type); - } - else - { - snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d", stream_type, stream_id); - props = gst_structure_from_string(stream_props, NULL); - g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL); - debug_log("stream_id[%d], stream_type[%s], result[%s].\n", stream_id, stream_type, stream_props); - } - - mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode); - mm_attrs_get_int_by_name(attrs, "sound_volume_type", &volume_type); - - switch (latency_mode) - { - case AUDIO_LATENCY_MODE_LOW: - latency = g_strndup("low", 3); - break; - case AUDIO_LATENCY_MODE_MID: - latency = g_strndup("mid", 3); - break; - case AUDIO_LATENCY_MODE_HIGH: - latency = g_strndup("high", 4); - break; - }; - - /* hook sound_type if emergency case */ - if (player->sound_focus.focus_changed_msg == MM_PLAYER_FOCUS_CHANGED_BY_EMERGENCY) - { - debug_log ("emergency session, hook sound_type from [%d] to [%d]\n", volume_type, MM_SOUND_VOLUME_TYPE_EMERGENCY); - volume_type = MM_SOUND_VOLUME_TYPE_EMERGENCY; - } -#if 0 //need to check - if (player->sound_focus.user_route_policy != 0) - { - route_path = player->sound_focus.user_route_policy; - } - - g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, - "latency", latency_mode, - NULL); - - debug_log("audiosink property status...volume type:%d, user-route=%d, latency=%d \n", - volume_type, route_path, latency_mode); - MMPLAYER_FLEAVE(); - -#endif - - g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, - "latency", latency, - NULL); - - debug_log("audiosink property - volume type=%d, latency=%s \n", - volume_type, latency); - - g_free(latency); - - MMPLAYER_FLEAVE(); -} - -static int -__mmplayer_gst_create_audio_pipeline(mm_player_t* player) -{ - MMPlayerGstElement* first_element = NULL; - MMPlayerGstElement* audiobin = NULL; - MMHandleType attrs = 0; - GstPad *pad = NULL; - GstPad *ghostpad = NULL; - GList* element_bucket = NULL; - gboolean link_audio_sink_now = TRUE; - int i =0; - - MMPLAYER_FENTER(); - - return_val_if_fail( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - /* alloc handles */ - audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM); - if ( ! audiobin ) - { - debug_error("failed to allocate memory for audiobin\n"); - return MM_ERROR_PLAYER_NO_FREE_SPACE; - } - - attrs = MMPLAYER_GET_ATTRS(player); - - /* create bin */ - audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN; - audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin"); - if ( !audiobin[MMPLAYER_A_BIN].gst ) - { - debug_error("failed to create audiobin\n"); - goto ERROR; - } - - /* take it */ - player->pipeline->audiobin = audiobin; - - player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player); - - /* Adding audiotp plugin for reverse trickplay feature */ -// MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player); - - /* converter */ - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player); - - /* resampler */ - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.name_of_audio_resampler, "audio resampler", TRUE, player); - - if (player->set_mode.pcm_extraction) // pcm extraction only and no sound output - { - if(player->audio_stream_render_cb_ex) - { - char *caps_str = NULL; - GstCaps* caps = NULL; - gchar *format = NULL; - - /* capsfilter */ - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player); - - mm_attrs_get_string_by_name (player->attrs, "pcm_audioformat", &format ); - - debug_log("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel); - - caps = gst_caps_new_simple ("audio/x-raw", - "format", G_TYPE_STRING, format, - "rate", G_TYPE_INT, player->pcm_samplerate, - "channels", G_TYPE_INT, player->pcm_channel, - NULL); - caps_str = gst_caps_to_string(caps); - debug_log("new caps : %s\n", caps_str); - - g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL ); - - /* clean */ - gst_caps_unref( caps ); - MMPLAYER_FREEIF( caps_str ); - - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player); - - g_object_set (G_OBJECT (audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL); - /* raw pad handling signal */ - MMPLAYER_SIGNAL_CONNECT( player, - (audiobin[MMPLAYER_A_DEINTERLEAVE].gst), - MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", - G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player); - } - else - { - int dst_samplerate = 0; - int dst_channels = 0; - int dst_depth = 0; - char *caps_str = NULL; - GstCaps* caps = NULL; - - /* get conf. values */ - mm_attrs_multiple_get(player->attrs, - NULL, - "pcm_extraction_samplerate", &dst_samplerate, - "pcm_extraction_channels", &dst_channels, - "pcm_extraction_depth", &dst_depth, - NULL); - - /* capsfilter */ - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player); - caps = gst_caps_new_simple ("audio/x-raw", - "rate", G_TYPE_INT, dst_samplerate, - "channels", G_TYPE_INT, dst_channels, - "depth", G_TYPE_INT, dst_depth, - NULL); - caps_str = gst_caps_to_string(caps); - debug_log("new caps : %s\n", caps_str); - - g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL ); - - /* clean */ - gst_caps_unref( caps ); - MMPLAYER_FREEIF( caps_str ); - - /* fake sink */ - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player); - - /* set sync */ - g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL); - } - } - else // normal playback - { - //GstCaps* caps = NULL; - gint channels = 0; - - /* for logical volume control */ - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player); - g_object_set(G_OBJECT (audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL); - - if (player->sound.mute) - { - debug_log("mute enabled\n"); - g_object_set(G_OBJECT (audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL); - } - -#if 0 - /*capsfilter */ - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player); - caps = gst_caps_from_string( "audio/x-raw-int, " - "endianness = (int) LITTLE_ENDIAN, " - "signed = (boolean) true, " - "width = (int) 16, " - "depth = (int) 16" ); - g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL ); - gst_caps_unref( caps ); -#endif - - /* chech if multi-chennels */ - if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) - { - GstPad *srcpad = NULL; - GstCaps *caps = NULL; - - if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) - { - if ((caps = gst_pad_query_caps(srcpad, NULL))) - { - //MMPLAYER_LOG_GST_CAPS_TYPE(caps); - GstStructure *str = gst_caps_get_structure(caps, 0); - if (str) - gst_structure_get_int (str, "channels", &channels); - gst_caps_unref(caps); - } - gst_object_unref(srcpad); - } - } - - /* audio effect element. if audio effect is enabled */ - if ( (strcmp(player->ini.name_of_audio_effect, "")) - && (channels <= 2) - && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom) ) - { - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.name_of_audio_effect, "audio effect filter", TRUE, player); - - debug_log("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type); - - if ( (!player->bypass_audio_effect) - && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom) ) - { - if ( MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type ) - { - if (!_mmplayer_audio_effect_custom_apply(player)) - { - debug_msg("apply audio effect(custom) setting success\n"); - } - } - } - - if ( (strcmp(player->ini.name_of_audio_effect_sec, "")) - && (player->set_mode.rich_audio) ) - { - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.name_of_audio_effect_sec, "audio effect filter", TRUE, player); - } - } - if (!MMPLAYER_IS_RTSP_STREAMING(player)) - { - if (player->set_mode.rich_audio && channels <= 2) - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VSP, "audiovsp", "x-speed", TRUE, player); - } - - /* create audio sink */ - MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.name_of_audiosink, "audiosink", link_audio_sink_now, player); - - /* qos on */ - g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */ - g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL); - - /* FIXIT : using system clock. isn't there another way? */ - if (player->videodec_linked) - { - debug_log("provide clock for movie = %s", (player->ini.provide_clock_for_movie)?"audio_clock":"sys_clock"); - g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "provide-clock", player->ini.provide_clock_for_movie, NULL); - } - else - { - debug_log("provide clock for music = %s", (player->ini.provide_clock_for_music)?"audio_clock":"sys_clock"); - g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "provide-clock", player->ini.provide_clock_for_music, NULL); - } - - if (g_strrstr(player->ini.name_of_audiosink, "pulsesink")) - __mmplayer_gst_set_audiosink_property(player, attrs); - } - - if (audiobin[MMPLAYER_A_SINK].gst) - { - GstPad *sink_pad = NULL; - sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink"); - MMPLAYER_SIGNAL_CONNECT (player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN, - "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player); - gst_object_unref (GST_OBJECT(sink_pad)); - } - - __mmplayer_add_sink( player, audiobin[MMPLAYER_A_SINK].gst ); - - /* adding created elements to bin */ - debug_log("adding created elements to bin\n"); - if( !__mmplayer_gst_element_add_bucket_to_bin( GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket )) - { - debug_error("failed to add elements\n"); - goto ERROR; - } - - /* linking elements in the bucket by added order. */ - debug_log("Linking elements in the bucket by added order.\n"); - if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 ) - { - debug_error("failed to link elements\n"); - goto ERROR; - } - - /* get first element's sinkpad for creating ghostpad */ - first_element = (MMPlayerGstElement *)element_bucket->data; - - pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink"); - if ( ! pad ) - { - debug_error("failed to get pad from first element of audiobin\n"); - goto ERROR; - } - - ghostpad = gst_ghost_pad_new("sink", pad); - if ( ! ghostpad ) - { - debug_error("failed to create ghostpad\n"); - goto ERROR; - } - - if ( FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad) ) - { - debug_error("failed to add ghostpad to audiobin\n"); - goto ERROR; - } - - player->gapless.audio_data_probe_id = gst_pad_add_probe(ghostpad, GST_PAD_PROBE_TYPE_BUFFER, - __mmplayer_audio_data_probe, player, NULL); - - gst_object_unref(pad); - - g_list_free(element_bucket); - - mm_attrs_set_int_by_name(attrs, "content_audio_found", TRUE); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; - -ERROR: - - debug_log("ERROR : releasing audiobin\n"); - - if ( pad ) - gst_object_unref(GST_OBJECT(pad)); - - if ( ghostpad ) - gst_object_unref(GST_OBJECT(ghostpad)); - - g_list_free( element_bucket ); - - /* release element which are not added to bin */ - for ( i = 1; i < MMPLAYER_A_NUM; i++ ) /* NOTE : skip bin */ - { - if ( audiobin[i].gst ) - { - GstObject* parent = NULL; - parent = gst_element_get_parent( audiobin[i].gst ); - - if ( !parent ) - { - gst_object_unref(GST_OBJECT(audiobin[i].gst)); - audiobin[i].gst = NULL; - } - else - { - gst_object_unref(GST_OBJECT(parent)); - } - } - } - - /* release audiobin with it's childs */ - if ( audiobin[MMPLAYER_A_BIN].gst ) - { - gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst)); - } - - MMPLAYER_FREEIF( audiobin ); - - player->pipeline->audiobin = NULL; - - return MM_ERROR_PLAYER_INTERNAL; -} - -static GstPadProbeReturn -__mmplayer_audio_stream_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data) -{ - mm_player_t* player = (mm_player_t*) u_data; - GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info); - GstMapInfo probe_info = GST_MAP_INFO_INIT; - - gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ); - - if (player->audio_stream_cb && probe_info.size && probe_info.data) - player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param); - - return GST_PAD_PROBE_OK; -} - -static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name) -{ - return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24); -} - -static GstPadProbeReturn -__mmplayer_video_stream_probe (GstPad *pad, GstPadProbeInfo *info, gpointer user_data) -{ - GstCaps *caps = NULL; - MMPlayerVideoStreamDataType stream; - MMVideoBuffer *video_buffer = NULL; - GstMemory *dataBlock = NULL; - GstMemory *metaBlock = NULL; - GstMapInfo mapinfo = GST_MAP_INFO_INIT; - GstStructure *structure = NULL; - const gchar *string_format = NULL; - unsigned int fourcc = 0; - mm_player_t* player = (mm_player_t*)user_data; - GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info); - - return_val_if_fail(buffer, GST_PAD_PROBE_DROP); - return_val_if_fail(gst_buffer_n_memory(buffer) , GST_PAD_PROBE_DROP); - - caps = gst_pad_get_current_caps(pad); - if (caps == NULL) { - debug_error( "Caps is NULL." ); - return GST_PAD_PROBE_OK; - } - - MMPLAYER_LOG_GST_CAPS_TYPE(caps); - - /* clear stream data structure */ - memset(&stream, 0x0, sizeof(MMPlayerVideoStreamDataType)); - - structure = gst_caps_get_structure( caps, 0 ); - gst_structure_get_int(structure, "width", &(stream.width)); - gst_structure_get_int(structure, "height", &(stream.height)); - string_format = gst_structure_get_string(structure, "format"); - if(string_format) { - fourcc = _mmplayer_convert_fourcc_string_to_value(string_format); - } - stream.format = util_get_pixtype(fourcc); - gst_caps_unref( caps ); - caps = NULL; - - /* - debug_log( "Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]", - GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format ); - */ - - if (stream.width == 0 || stream.height == 0 || stream.format == MM_PIXEL_FORMAT_INVALID) { - debug_error("Wrong condition!!"); - return TRUE; - } - - /* set size and timestamp */ - dataBlock = gst_buffer_peek_memory(buffer, 0); - stream.length_total = gst_memory_get_sizes(dataBlock, NULL, NULL); - stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */ - - /* check zero-copy */ - if (player->set_mode.video_zc && - player->set_mode.media_packet_video_stream && - gst_buffer_n_memory(buffer) > 1) { - metaBlock = gst_buffer_peek_memory(buffer, 1); - gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ); - video_buffer = (MMVideoBuffer *)mapinfo.data; - } - - if (video_buffer) { - /* set tbm bo */ - if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) { - /* copy pointer of tbm bo, stride, elevation */ - memcpy(stream.bo, video_buffer->handle.bo, - sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX); - } - else if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_PHYSICAL_ADDRESS) { - memcpy(stream.data, video_buffer->data, - sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX); - } - memcpy(stream.stride, video_buffer->stride_width, - sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX); - memcpy(stream.elevation, video_buffer->stride_height, - sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX); - /* set gst buffer */ - stream.internal_buffer = buffer; - } else { - tbm_bo_handle thandle; - int stride = ((stream.width + 3) & (~3)); - int elevation = stream.height; - int size = stride * elevation * 3 / 2; - gboolean gst_ret; - gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE); - if(!gst_ret) { - debug_error("fail to gst_memory_map"); - return GST_PAD_PROBE_OK; - } - - stream.stride[0] = stride; - stream.elevation[0] = elevation; - if(stream.format == MM_PIXEL_FORMAT_I420) { - stream.stride[1] = stream.stride[2] = stride / 2; - stream.elevation[1] = stream.elevation[2] = elevation / 2; - } - else { - debug_error("default #plane is 2, format %d", stream.format); - stream.stride[1] = stride; - stream.elevation[1] = elevation / 2; - } - - stream.bo[0] = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT); - if(!stream.bo[0]) { - debug_error("Fail to tbm_bo_alloc!!"); - return TRUE; - } - thandle = tbm_bo_map(stream.bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE); - if(thandle.ptr && mapinfo.data) - memcpy(thandle.ptr, mapinfo.data, size); - else - debug_error("data pointer is wrong. dest : %p, src : %p", - thandle.ptr, mapinfo.data); - - tbm_bo_unmap(stream.bo[0]); - } - - if (player->video_stream_cb) { - player->video_stream_cb(&stream, player->video_stream_cb_user_param); - } - - if (metaBlock) { - gst_memory_unmap(metaBlock, &mapinfo); - }else { - gst_memory_unmap(dataBlock, &mapinfo); - tbm_bo_unref(stream.bo[0]); - } - - return GST_PAD_PROBE_OK; -} - -static int -__mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket, gboolean use_video_stream) -{ - gchar* video_csc = "videoconvert"; // default colorspace converter - GList* element_bucket = *bucket; - - return_val_if_fail(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_FENTER(); - - if (!player->set_mode.media_packet_video_stream && use_video_stream) - { - if (player->set_mode.video_zc && strlen(player->ini.name_of_video_converter) > 0) - { - video_csc = player->ini.name_of_video_converter; - } - - MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player); - debug_log("using video converter: %s", video_csc); - - if ( !player->set_mode.video_zc) - { - gint width = 0; //width of video - gint height = 0; //height of video - GstCaps* video_caps = NULL; - GstStructure *structure = NULL; - - /* rotator, scaler and capsfilter */ - MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player); - MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_SCALE, "videoscale", "video scaler", TRUE, player); - MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CAPS, "capsfilter", "videocapsfilter", TRUE, player); - - /* get video stream caps parsed by demuxer */ - - mm_attrs_get_int_by_name(player->attrs, "display_width", &width); - - if(width) - structure = gst_structure_new("video/x-raw", "width", G_TYPE_INT, width, NULL); - - mm_attrs_get_int_by_name(player->attrs, "display_height", &height); - - if(structure && height) { - gst_structure_set (structure, "height", G_TYPE_INT, height, NULL); - - video_caps = gst_caps_new_full(structure, NULL); - g_object_set (GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_CAPS].gst), "caps", video_caps, NULL ); - MMPLAYER_LOG_GST_CAPS_TYPE(video_caps); - gst_caps_unref(video_caps); - } - else - debug_error("fail to set capsfilter %p, width %d, height %d", structure, width, height); - - if(structure) - gst_structure_free(structure); - - } - } - else - { - MMDisplaySurfaceType surface_type = MM_DISPLAY_SURFACE_NULL; - mm_attrs_get_int_by_name (player->attrs, "display_surface_type", (int *)&surface_type); - - if (player->set_mode.video_zc) - { - if ( (surface_type == MM_DISPLAY_SURFACE_EVAS) && ( !strcmp(player->ini.videosink_element_evas, "evasimagesink")) ) - { - video_csc = player->ini.name_of_video_converter; - } - else - { - video_csc = ""; - } - } - - if (video_csc && (strcmp(video_csc, ""))) - { - MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player); - debug_log("using video converter: %s", video_csc); - } - - /* set video rotator */ - if ( !player->set_mode.video_zc ) - MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player); - - /* videoscaler */ - #if !defined(__arm__) - MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_SCALE, "videoscale", "videoscaler", TRUE, player); - #endif - } - - *bucket = element_bucket; - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; - -ERROR: - *bucket = NULL; - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_INTERNAL; -} - -/** - * This function is to create video pipeline. - * - * @param player [in] handle of player - * caps [in] src caps of decoder - * surface_type [in] surface type for video rendering - * - * @return This function returns zero on success. - * @remark - * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline - */ -/** - * VIDEO PIPELINE - * - x surface (arm/x86) : xvimagesink - * - evas surface (arm) : evaspixmapsink - * fimcconvert ! evasimagesink - * - evas surface (x86) : videoconvertor ! videoflip ! evasimagesink - */ -static int -__mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type) -{ - GstPad *pad = NULL; - MMHandleType attrs; - GList*element_bucket = NULL; - MMPlayerGstElement* first_element = NULL; - MMPlayerGstElement* videobin = NULL; - gchar *videosink_element = NULL; - - MMPLAYER_FENTER(); - - return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - - /* alloc handles */ - videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM); - if ( !videobin ) - { - return MM_ERROR_PLAYER_NO_FREE_SPACE; - } - - player->pipeline->videobin = videobin; - - attrs = MMPLAYER_GET_ATTRS(player); - if ( !attrs ) - { - debug_error("cannot get content attribute"); - return MM_ERROR_PLAYER_INTERNAL; - } - - /* create bin */ - videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN; - videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin"); - if ( !videobin[MMPLAYER_V_BIN].gst ) - { - debug_error("failed to create videobin"); - goto ERROR; - } - - if( player->use_video_stream ) // video stream callback, so send raw video data to application - { - debug_log("using memsink\n"); - - if ( __mmplayer_gst_create_video_filters(player, &element_bucket, TRUE) != MM_ERROR_NONE) - goto ERROR; - - /* finally, create video sink. output will be BGRA8888. */ - MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, "avsysmemsink", "videosink", TRUE, player); - - MMPLAYER_SIGNAL_CONNECT( player, - videobin[MMPLAYER_V_SINK].gst, - MM_PLAYER_SIGNAL_TYPE_VIDEOBIN, - "video-stream", - G_CALLBACK(__mmplayer_videostream_cb), - player ); - } - else // render video data using sink plugin like xvimagesink - { - if ( __mmplayer_gst_create_video_filters(player, &element_bucket, FALSE) != MM_ERROR_NONE) - goto ERROR; - - /* set video sink */ - switch (surface_type) - { - case MM_DISPLAY_SURFACE_X: - if (strlen(player->ini.videosink_element_x) > 0) - videosink_element = player->ini.videosink_element_x; - else - goto ERROR; - break; - case MM_DISPLAY_SURFACE_EVAS: - if (strlen(player->ini.videosink_element_evas) > 0) - videosink_element = player->ini.videosink_element_evas; - else - goto ERROR; - break; - case MM_DISPLAY_SURFACE_X_EXT: - { - void *pixmap_id_cb = NULL; - mm_attrs_get_data_by_name(attrs, "display_overlay", &pixmap_id_cb); - if (pixmap_id_cb) /* this is used for the videoTextue(canvasTexture) overlay */ - { - videosink_element = player->ini.videosink_element_x; - } - else - { - debug_error("something wrong.. callback function for getting pixmap id is null"); - goto ERROR; - } - break; - } - case MM_DISPLAY_SURFACE_NULL: - if (strlen(player->ini.videosink_element_fake) > 0) - videosink_element = player->ini.videosink_element_fake; - else - goto ERROR; - break; - case MM_DISPLAY_SURFACE_REMOTE: - if (strlen(player->ini.videosink_element_remote) > 0) - videosink_element = player->ini.videosink_element_remote; - else - goto ERROR; - break; - default: - debug_error("unidentified surface type"); - goto ERROR; - } - - MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE, player); - debug_log("selected videosink name: %s", videosink_element); - - /* additional setting for sink plug-in */ - switch (surface_type) { - case MM_DISPLAY_SURFACE_X_EXT: - MMPLAYER_SIGNAL_CONNECT( player, - player->pipeline->videobin[MMPLAYER_V_SINK].gst, - MM_PLAYER_SIGNAL_TYPE_VIDEOBIN, - "frame-render-error", - G_CALLBACK(__mmplayer_videoframe_render_error_cb), - player ); - debug_log("videoTexture usage, connect a signal handler for pixmap rendering error"); - break; - case MM_DISPLAY_SURFACE_REMOTE: - { - char *stream_path = NULL; - int attr_ret = mm_attrs_get_string_by_name ( - attrs, "shm_stream_path", &stream_path ); - if(attr_ret == MM_ERROR_NONE && stream_path) { - g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), - "socket-path", stream_path, - "wait-for-connection", FALSE, - "sync", TRUE, - NULL); - debug_log("set path \"%s\" for shmsink", stream_path); - } else { - debug_error("Not set attribute of shm_stream_path"); - goto ERROR; - } - break; - } - default: - break; - } - } - - if (_mmplayer_update_video_param(player) != MM_ERROR_NONE) - goto ERROR; - - if (videobin[MMPLAYER_V_SINK].gst) - { - GstPad *sink_pad = NULL; - sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink"); - if (sink_pad) - { - MMPLAYER_SIGNAL_CONNECT (player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN, - "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player); - gst_object_unref (GST_OBJECT(sink_pad)); - } - else - { - debug_warning("failed to get sink pad from videosink\n"); - } - } - - /* store it as it's sink element */ - __mmplayer_add_sink( player, videobin[MMPLAYER_V_SINK].gst ); - - /* adding created elements to bin */ - if( ! __mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket) ) - { - debug_error("failed to add elements\n"); - goto ERROR; - } - - /* Linking elements in the bucket by added order */ - if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 ) - { - debug_error("failed to link elements\n"); - goto ERROR; - } - - /* get first element's sinkpad for creating ghostpad */ - first_element = (MMPlayerGstElement *)element_bucket->data; - if ( !first_element ) - { - debug_error("failed to get first element from bucket\n"); - goto ERROR; - } - - pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink"); - if ( !pad ) - { - debug_error("failed to get pad from first element\n"); - goto ERROR; - } - - /* create ghostpad */ - player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad); - if ( FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin) ) - { - debug_error("failed to add ghostpad to videobin\n"); - goto ERROR; - } - gst_object_unref(pad); - - /* done. free allocated variables */ - g_list_free(element_bucket); - - mm_attrs_set_int_by_name(attrs, "content_video_found", TRUE); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; - -ERROR: - debug_error("ERROR : releasing videobin\n"); - - g_list_free( element_bucket ); - - if (pad) - gst_object_unref(GST_OBJECT(pad)); - - /* release videobin with it's childs */ - if ( videobin[MMPLAYER_V_BIN].gst ) - { - gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst)); - } - - - MMPLAYER_FREEIF( videobin ); - - player->pipeline->videobin = NULL; - - return MM_ERROR_PLAYER_INTERNAL; -} - -static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player) -{ - GList *element_bucket = NULL; - MMPlayerGstElement *textbin = player->pipeline->textbin; - - MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player); - MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player); - g_object_set (G_OBJECT (textbin[MMPLAYER_T_IDENTITY].gst), - "signal-handoffs", FALSE, - NULL); - - MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player); - MMPLAYER_SIGNAL_CONNECT( player, - G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), - MM_PLAYER_SIGNAL_TYPE_TEXTBIN, - "handoff", - G_CALLBACK(__mmplayer_update_subtitle), - (gpointer)player ); - - g_object_set (G_OBJECT (textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL); - g_object_set (G_OBJECT (textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL); - g_object_set (G_OBJECT (textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL); - - if (!player->play_subtitle) - { - debug_log ("add textbin sink as sink element of whole pipeline.\n"); - __mmplayer_add_sink (player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst)); - } - - /* adding created elements to bin */ - debug_log("adding created elements to bin\n"); - if( !__mmplayer_gst_element_add_bucket_to_bin( GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket )) - { - debug_error("failed to add elements\n"); - goto ERROR; - } - - /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */ - GST_OBJECT_FLAG_UNSET (textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK); - GST_OBJECT_FLAG_UNSET (textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK); - - /* linking elements in the bucket by added order. */ - debug_log("Linking elements in the bucket by added order.\n"); - if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 ) - { - debug_error("failed to link elements\n"); - goto ERROR; - } - - /* done. free allocated variables */ - g_list_free(element_bucket); - - if (textbin[MMPLAYER_T_QUEUE].gst) - { - GstPad *pad = NULL; - GstPad *ghostpad = NULL; - - pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink"); - if (!pad) - { - debug_error("failed to get video pad of textbin\n"); - return MM_ERROR_PLAYER_INTERNAL; - } - - ghostpad = gst_ghost_pad_new("text_sink", pad); - gst_object_unref(pad); - - if (!ghostpad) - { - debug_error("failed to create ghostpad of textbin\n"); - goto ERROR; - } - - if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) - { - debug_error("failed to add ghostpad to textbin\n"); - goto ERROR; - } - } - - return MM_ERROR_NONE; - -ERROR: - g_list_free(element_bucket); - - return MM_ERROR_PLAYER_INTERNAL; -} - -static int __mmplayer_gst_create_text_pipeline(mm_player_t* player) -{ - MMPlayerGstElement *textbin = NULL; - GList *element_bucket = NULL; - gint i = 0; - - MMPLAYER_FENTER(); - - return_val_if_fail( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - /* alloc handles */ - textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM); - if ( ! textbin ) - { - debug_error("failed to allocate memory for textbin\n"); - return MM_ERROR_PLAYER_NO_FREE_SPACE; - } - - /* create bin */ - textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN; - textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin"); - if ( !textbin[MMPLAYER_T_BIN].gst ) - { - debug_error("failed to create textbin\n"); - goto ERROR; - } - - /* take it */ - player->pipeline->textbin = textbin; - - /* fakesink */ - if (player->use_textoverlay) - { - debug_log ("use textoverlay for displaying \n"); - - MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_QUEUE, "queue", "text_t_queue", textbin[MMPLAYER_T_BIN].gst, player); - - MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_QUEUE, "queue", "text_v_queue", textbin[MMPLAYER_T_BIN].gst, player); - - MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_CONVERTER, "fimcconvert", "text_v_converter", textbin[MMPLAYER_T_BIN].gst, player); - - MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_OVERLAY, "textoverlay", "text_overlay", textbin[MMPLAYER_T_BIN].gst, player); - - if (!gst_element_link_pads (textbin[MMPLAYER_T_VIDEO_QUEUE].gst, "src", textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "sink")) - { - debug_error("failed to link queue and converter\n"); - goto ERROR; - } - - if (!gst_element_link_pads (textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "video_sink")) - { - debug_error("failed to link queue and textoverlay\n"); - goto ERROR; - } - - if (!gst_element_link_pads (textbin[MMPLAYER_T_QUEUE].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "text_sink")) - { - debug_error("failed to link queue and textoverlay\n"); - goto ERROR; - } - } - else - { - int surface_type = 0; - - debug_log ("use subtitle message for displaying \n"); - - mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type); - - switch(surface_type) - { - case MM_DISPLAY_SURFACE_X: - case MM_DISPLAY_SURFACE_EVAS: - case MM_DISPLAY_SURFACE_GL: - case MM_DISPLAY_SURFACE_NULL: - case MM_DISPLAY_SURFACE_X_EXT: - case MM_DISPLAY_SURFACE_REMOTE: - if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) - { - debug_error("failed to make plain text elements\n"); - goto ERROR; - } - break; - - default: - break; - } - } - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; - -ERROR: - - debug_log("ERROR : releasing textbin\n"); - - g_list_free( element_bucket ); - - /* release element which are not added to bin */ - for ( i = 1; i < MMPLAYER_T_NUM; i++ ) /* NOTE : skip bin */ - { - if ( textbin[i].gst ) - { - GstObject* parent = NULL; - parent = gst_element_get_parent( textbin[i].gst ); - - if ( !parent ) - { - gst_object_unref(GST_OBJECT(textbin[i].gst)); - textbin[i].gst = NULL; - } - else - { - gst_object_unref(GST_OBJECT(parent)); - } - } - } - - /* release textbin with it's childs */ - if ( textbin[MMPLAYER_T_BIN].gst ) - { - gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst)); - } - - MMPLAYER_FREEIF( textbin ); - - player->pipeline->textbin = NULL; - - return MM_ERROR_PLAYER_INTERNAL; -} - - -static int -__mmplayer_gst_create_subtitle_src(mm_player_t* player) -{ - MMPlayerGstElement* mainbin = NULL; - MMHandleType attrs = 0; - GstElement *subsrc = NULL; - GstElement *subparse = NULL; - gchar *subtitle_uri =NULL; - const gchar *charset = NULL; - GstPad *pad = NULL; - - MMPLAYER_FENTER(); - - /* get mainbin */ - return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - - mainbin = player->pipeline->mainbin; - - attrs = MMPLAYER_GET_ATTRS(player); - if ( !attrs ) - { - debug_error("cannot get content attribute\n"); - return MM_ERROR_PLAYER_INTERNAL; - } - - mm_attrs_get_string_by_name ( attrs, "subtitle_uri", &subtitle_uri ); - if ( !subtitle_uri || strlen(subtitle_uri) < 1) - { - debug_error("subtitle uri is not proper filepath.\n"); - return MM_ERROR_PLAYER_INVALID_URI; - } - debug_log("subtitle file path is [%s].\n", subtitle_uri); - - - /* create the subtitle source */ - subsrc = gst_element_factory_make("filesrc", "subtitle_source"); - if ( !subsrc ) - { - debug_error ( "failed to create filesrc element\n" ); - goto ERROR; - } - g_object_set(G_OBJECT (subsrc), "location", subtitle_uri, NULL); - - mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC; - mainbin[MMPLAYER_M_SUBSRC].gst = subsrc; - - if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) - { - debug_warning("failed to add queue\n"); - goto ERROR; - } - - /* subparse */ - subparse = gst_element_factory_make("subparse", "subtitle_parser"); - if ( !subparse ) - { - debug_error ( "failed to create subparse element\n" ); - goto ERROR; - } - - charset = util_get_charset(subtitle_uri); - if (charset) - { - debug_log ("detected charset is %s\n", charset ); - g_object_set (G_OBJECT (subparse), "subtitle-encoding", charset, NULL); - } - - mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE; - mainbin[MMPLAYER_M_SUBPARSE].gst = subparse; - - if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) - { - debug_warning("failed to add subparse\n"); - goto ERROR; - } - - if (!gst_element_link_pads (subsrc, "src", subparse, "sink")) - { - debug_warning("failed to link subsrc and subparse\n"); - goto ERROR; - } - - player->play_subtitle = TRUE; - player->adjust_subtitle_pos = 0; - - debug_log ("play subtitle using subtitle file\n"); - - if (player->pipeline->textbin == NULL) - { - if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) - { - debug_error("failed to create textbin. continuing without text\n"); - goto ERROR; - } - - if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst))) - { - debug_warning("failed to add textbin\n"); - goto ERROR; - } - - debug_log ("link text input selector and textbin ghost pad"); - - player->textsink_linked = 1; - player->external_text_idx = 0; - debug_msg("player->textsink_linked set to 1\n"); - } - else - { - debug_log("text bin has been created. reuse it."); - player->external_text_idx = 1; - } - - if (!gst_element_link_pads (subparse, "src", player->pipeline->textbin[MMPLAYER_T_BIN].gst, "text_sink")) - { - debug_warning("failed to link subparse and textbin\n"); - goto ERROR; - } - - pad = gst_element_get_static_pad (player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst, "sink"); - - if (!pad) - { - debug_error("failed to get sink pad from textsink to probe data"); - return MM_ERROR_PLAYER_INTERNAL; - } - - gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, - __mmplayer_subtitle_adjust_position_probe, player, NULL); - - gst_object_unref(pad); - pad=NULL; - - /* create dot. for debugging */ - MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-with-subtitle" ); - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; - -ERROR: - player->textsink_linked = 0; - return MM_ERROR_PLAYER_INTERNAL; -} - -gboolean -__mmplayer_update_subtitle( GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data) -{ - mm_player_t* player = (mm_player_t*) data; - MMMessageParamType msg = {0, }; - GstClockTime duration = 0; - gpointer text = NULL; - guint text_size = 0; - gboolean ret = TRUE; - GstMapInfo mapinfo = GST_MAP_INFO_INIT; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, FALSE ); - return_val_if_fail ( buffer, FALSE ); - - gst_buffer_map(buffer, &mapinfo, GST_MAP_READ); - text = g_memdup(mapinfo.data, mapinfo.size); - text_size = mapinfo.size; - duration = GST_BUFFER_DURATION(buffer); - - - if ( player->set_mode.subtitle_off ) - { - debug_log("subtitle is OFF.\n" ); - return TRUE; - } - - if ( !text || (text_size == 0)) - { - debug_log("There is no subtitle to be displayed.\n" ); - return TRUE; - } - - msg.data = (void *) text; - msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration); - - debug_log("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data ); - - MMPLAYER_POST_MSG( player, MM_MESSAGE_UPDATE_SUBTITLE, &msg ); - gst_buffer_unmap(buffer, &mapinfo); - - MMPLAYER_FLEAVE(); - - return ret; -} - -static GstPadProbeReturn -__mmplayer_subtitle_adjust_position_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data) - -{ - mm_player_t *player = (mm_player_t *) u_data; - GstClockTime cur_timestamp = 0; - gint64 adjusted_timestamp = 0; - GstBuffer *buffer = gst_pad_probe_info_get_buffer(info); - - return_val_if_fail ( player, FALSE ); - - if ( player->set_mode.subtitle_off ) - { - debug_log("subtitle is OFF.\n" ); - return TRUE; - } - - if (player->adjust_subtitle_pos == 0 ) - { - debug_log("nothing to do"); - return TRUE; - } - - cur_timestamp = GST_BUFFER_TIMESTAMP(buffer); - adjusted_timestamp = (gint64) cur_timestamp + ((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000)); - - if ( adjusted_timestamp < 0) - { - debug_log("adjusted_timestamp under zero"); - MMPLAYER_FLEAVE(); - return FALSE; - } - - GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp; - debug_log("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "", - GST_TIME_ARGS(cur_timestamp), - GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer))); - - return GST_PAD_PROBE_OK; -} -static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position) -{ - MMPLAYER_FENTER(); - - /* check player and subtitlebin are created */ - return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED ); - return_val_if_fail ( player->play_subtitle, MM_ERROR_NOT_SUPPORT_API ); - - if (position == 0) - { - debug_log ("nothing to do\n"); - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; - } - - switch (format) - { - case MM_PLAYER_POS_FORMAT_TIME: - { - /* check current postion */ - player->adjust_subtitle_pos = position; - - debug_log("save adjust_subtitle_pos in player") ; - } - break; - - default: - { - debug_warning("invalid format.\n"); - MMPLAYER_FLEAVE(); - return MM_ERROR_INVALID_ARGUMENT; - } - } - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} -static int __gst_adjust_video_position(mm_player_t* player, int offset) -{ - MMPLAYER_FENTER(); - debug_log("adjusting video_pos in player") ; - int current_pos = 0; - /* check player and videobin are created */ - return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED ); - if ( !player->pipeline->videobin || - !player->pipeline->videobin[MMPLAYER_V_SINK].gst ) - { - debug_log("no video pipeline or sink is there"); - return MM_ERROR_PLAYER_INVALID_STATE ; - } - if (offset == 0) - { - debug_log ("nothing to do\n"); - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; - } - if(__gst_get_position ( player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)¤t_pos ) != MM_ERROR_NONE ) - { - debug_log("failed to get current position"); - return MM_ERROR_PLAYER_INTERNAL; - } - if ( (current_pos - offset ) < GST_TIME_AS_MSECONDS(player->duration) ) - { - debug_log("enter video delay is valid"); - } - else { - debug_log("enter video delay is crossing content boundary"); - return MM_ERROR_INVALID_ARGUMENT ; - } - g_object_set (G_OBJECT (player->pipeline->videobin[MMPLAYER_V_SINK].gst),"ts-offset",((gint64) offset * G_GINT64_CONSTANT(1000000)),NULL); - debug_log("video delay has been done"); - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -static void -__gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data) // @ -{ - GstElement *appsrc = element; - tBuffer *buf = (tBuffer *)user_data; - GstBuffer *buffer = NULL; - GstFlowReturn ret = GST_FLOW_OK; - gint len = size; - - return_if_fail ( element ); - return_if_fail ( buf ); - - buffer = gst_buffer_new (); - - if (buf->offset >= buf->len) - { - debug_log("call eos appsrc\n"); - g_signal_emit_by_name (appsrc, "end-of-stream", &ret); - return; - } - - if ( buf->len - buf->offset < size) - { - len = buf->len - buf->offset + buf->offset; - } - - gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, (guint8*)(buf->buf + buf->offset), g_free)); - GST_BUFFER_OFFSET(buffer) = buf->offset; - GST_BUFFER_OFFSET_END(buffer) = buf->offset + len; - - //debug_log("feed buffer %p, offset %u-%u length %u\n", buffer, buf->offset, buf->len,len); - g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret); - - buf->offset += len; -} - -static gboolean -__gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data) // @ -{ - tBuffer *buf = (tBuffer *)user_data; - - return_val_if_fail ( buf, FALSE ); - - buf->offset = (int)size; - - return TRUE; -} - -static void -__gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data) // @ -{ - mm_player_t *player = (mm_player_t*)user_data; - MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT; - - return_if_fail ( player ); - - debug_msg("app-src: feed data\n"); - - if (player->media_stream_buffer_status_cb[type]) - player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, player->buffer_cb_user_param); -} - -static gboolean -__gst_appsrc_seek_data(GstElement *element, guint64 offset, gpointer user_data) // @ -{ - mm_player_t *player = (mm_player_t*)user_data; - MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT; - - return_val_if_fail ( player, FALSE ); - - debug_msg("app-src: seek data\n"); - - if(player->media_stream_seek_data_cb[type]) - player->media_stream_seek_data_cb[type](type, offset, player->buffer_cb_user_param); - - return TRUE; -} - - -static gboolean -__gst_appsrc_enough_data(GstElement *element, gpointer user_data) // @ -{ - mm_player_t *player = (mm_player_t*)user_data; - MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT; - - return_val_if_fail ( player, FALSE ); - - debug_msg("app-src: enough data:%p\n", player->media_stream_buffer_status_cb[type]); - - if (player->media_stream_buffer_status_cb[type]) - player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, player->buffer_cb_user_param); - - return TRUE; -} - -int -_mmplayer_push_buffer(MMHandleType hplayer, unsigned char *buf, int size) // @ -{ - mm_player_t* player = (mm_player_t*)hplayer; - GstBuffer *buffer = NULL; - GstFlowReturn gst_ret = GST_FLOW_OK; - int ret = MM_ERROR_NONE; -// gint len = size; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - /* check current state */ -// MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_START ); - - - /* NOTE : we should check and create pipeline again if not created as we destroy - * whole pipeline when stopping in streamming playback - */ - if ( ! player->pipeline ) - { - if ( MM_ERROR_NONE != __gst_realize( player ) ) - { - debug_error("failed to realize before starting. only in streamming\n"); - return MM_ERROR_PLAYER_INTERNAL; - } - } - - debug_msg("app-src: pushing data\n"); - - if ( buf == NULL ) - { - debug_error("buf is null\n"); - return MM_ERROR_NONE; - } - - buffer = gst_buffer_new (); - - if (size <= 0) - { - debug_log("call eos appsrc\n"); - g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "end-of-stream", &gst_ret); - return MM_ERROR_NONE; - } - - //gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, (guint8*)(buf->buf + buf->offset), g_free)); - - debug_log("feed buffer %p, length %u\n", buf, size); - g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "push-buffer", buffer, &gst_ret); - - MMPLAYER_FLEAVE(); - - return ret; -} - -/* if retval is FALSE, it will be dropped for perfomance. */ -static gboolean -__mmplayer_check_useful_message(mm_player_t *player, GstMessage * message) -{ - gboolean retval = FALSE; - - if ( !(player->pipeline && player->pipeline->mainbin) ) - { - debug_error("player pipeline handle is null"); - return TRUE; - } - - switch (GST_MESSAGE_TYPE (message)) - { - case GST_MESSAGE_TAG: - case GST_MESSAGE_EOS: - case GST_MESSAGE_ERROR: - case GST_MESSAGE_WARNING: - case GST_MESSAGE_CLOCK_LOST: - case GST_MESSAGE_NEW_CLOCK: - case GST_MESSAGE_ELEMENT: - case GST_MESSAGE_DURATION_CHANGED: - case GST_MESSAGE_ASYNC_START: - retval = TRUE; - break; - case GST_MESSAGE_ASYNC_DONE: - case GST_MESSAGE_STATE_CHANGED: - /* we only handle messages from pipeline */ - if(( message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst ) && (!player->gapless.reconfigure)) - retval = TRUE; - else - retval = FALSE; - break; - case GST_MESSAGE_BUFFERING: - { - gint buffer_percent = 0; - - gst_message_parse_buffering (message, &buffer_percent); - - if ((MMPLAYER_IS_STREAMING(player)) && - (player->streamer) && - (player->streamer->is_buffering == TRUE) && - (buffer_percent == MAX_BUFFER_PERCENT)) - { - debug_log (">>> [%s] Buffering DONE is detected !!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message))); - player->streamer->is_buffering_done = TRUE; - } - - retval = TRUE; - break; - } - default: - retval = FALSE; - break; - } - - return retval; -} - -GstBusSyncReply -__mmplayer_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data) -{ - mm_player_t *player = (mm_player_t *)data; - GstBusSyncReply reply = GST_BUS_DROP; - - if ( ! ( player->pipeline && player->pipeline->mainbin ) ) - { - debug_error("player pipeline handle is null"); - return GST_BUS_PASS; - } - - if (!__mmplayer_check_useful_message(player, message)) - { - gst_message_unref (message); - return GST_BUS_DROP; - } - - switch (GST_MESSAGE_TYPE (message)) - { - case GST_MESSAGE_STATE_CHANGED: - /* post directly for fast launch */ - if (player->sync_handler) { - __mmplayer_gst_callback(NULL, message, player); - reply = GST_BUS_DROP; - } - else { - reply = GST_BUS_PASS; - } - break; - case GST_MESSAGE_TAG: - __mmplayer_gst_extract_tag_from_msg(player, message); - - #if 0 // debug - { - GstTagList *tags = NULL; - - gst_message_parse_tag (message, &tags); - if (tags) { - debug_error("TAGS received from element \"%s\".\n", - GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message)))); - - gst_tag_list_foreach (tags, print_tag, NULL); - gst_tag_list_free (tags); - tags = NULL; - } - break; - } - #endif - break; - - case GST_MESSAGE_DURATION_CHANGED: - __mmplayer_gst_handle_duration(player, message); - break; - case GST_MESSAGE_ASYNC_DONE: - /* NOTE:Don't call gst_callback directly - * because previous frame can be showed even though this message is received for seek. - */ - default: - reply = GST_BUS_PASS; - break; - } - - if (reply == GST_BUS_DROP) - gst_message_unref (message); - - return reply; -} - -static gboolean -__mmplayer_gst_create_decoder ( mm_player_t *player, - MMPlayerTrackType track, - GstPad* srcpad, - enum MainElementID elemId, - const gchar* name) -{ - gboolean ret = TRUE; - GstPad *sinkpad = NULL; - - MMPLAYER_FENTER(); - - return_val_if_fail( player && - player->pipeline && - player->pipeline->mainbin, FALSE); - return_val_if_fail((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE); - return_val_if_fail(srcpad, FALSE); - return_val_if_fail((player->pipeline->mainbin[elemId].gst == NULL), FALSE); - - GstElement *decodebin = NULL; - GstCaps *dec_caps = NULL; - - /* create decodebin */ - decodebin = gst_element_factory_make("decodebin", name); - - if (!decodebin) - { - debug_error("error : fail to create decodebin for %d decoder\n", track); - ret = FALSE; - goto ERROR; - } - - /* raw pad handling signal */ - MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", - G_CALLBACK(__mmplayer_gst_decode_pad_added), player); - - /* This signal is emitted whenever decodebin finds a new stream. It is emitted - before looking for any elements that can handle that stream.*/ - MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", - G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player); - - /* This signal is emitted when a element is added to the bin.*/ - MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added", - G_CALLBACK(__mmplayer_gst_element_added), player); - - if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) - { - debug_error("failed to add new decodebin\n"); - ret = FALSE; - goto ERROR; - } - - dec_caps = gst_pad_query_caps (srcpad, NULL); - if (dec_caps) - { - //debug_log ("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps); - g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL); - gst_caps_unref(dec_caps); - } - - player->pipeline->mainbin[elemId].id = elemId; - player->pipeline->mainbin[elemId].gst = decodebin; - - sinkpad = gst_element_get_static_pad (decodebin, "sink"); - - if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) - { - debug_warning ("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad)); - gst_object_unref (GST_OBJECT(decodebin)); - } - - if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent (decodebin)) - { - debug_error("failed to sync second level decodebin state with parent\n"); - } - - debug_log("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num); - -ERROR: - if (sinkpad) - { - gst_object_unref ( GST_OBJECT(sinkpad) ); - sinkpad = NULL; - } - MMPLAYER_FLEAVE(); - - return ret; -} - -/** - * This function is to create audio or video pipeline for playing. - * - * @param player [in] handle of player - * - * @return This function returns zero on success. - * @remark - * @see - */ -static int -__mmplayer_gst_create_pipeline(mm_player_t* player) // @ -{ - GstBus *bus = NULL; - MMPlayerGstElement *mainbin = NULL; - MMHandleType attrs = 0; - GstElement* element = NULL; - GstElement* elem_src_audio = NULL; - GstElement* elem_src_subtitle = NULL; - GstElement* es_video_queue = NULL; - GstElement* es_audio_queue = NULL; - GstElement* es_subtitle_queue = NULL; - GList* element_bucket = NULL; - gboolean need_state_holder = TRUE; - gint i = 0; - - MMPLAYER_FENTER(); - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - /* get profile attribute */ - attrs = MMPLAYER_GET_ATTRS(player); - if ( !attrs ) - { - debug_error("cannot get content attribute\n"); - goto INIT_ERROR; - } - - /* create pipeline handles */ - if ( player->pipeline ) - { - debug_warning("pipeline should be released before create new one\n"); - goto INIT_ERROR; - } - - player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0( sizeof(MMPlayerGstPipelineInfo) ); - if (player->pipeline == NULL) - goto INIT_ERROR; - - memset( player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo) ); - - - /* create mainbin */ - mainbin = (MMPlayerGstElement*) g_malloc0( sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM ); - if (mainbin == NULL) - goto INIT_ERROR; - - memset( mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); - - /* create pipeline */ - mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE; - mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player"); - if ( ! mainbin[MMPLAYER_M_PIPE].gst ) - { - debug_error("failed to create pipeline\n"); - goto INIT_ERROR; - } - player->demux_pad_index = 0; - player->subtitle_language_list = NULL; - - player->is_subtitle_force_drop = FALSE; - player->last_multiwin_status = FALSE; - - _mmplayer_track_initialize(player); - - /* create source element */ - switch ( player->profile.uri_type ) - { - /* rtsp streamming */ - case MM_PLAYER_URI_TYPE_URL_RTSP: - { - gint network_bandwidth; - gchar *user_agent, *wap_profile; - - element = gst_element_factory_make(player->ini.name_of_rtspsrc, "streaming_source"); - - if ( !element ) - { - debug_error("failed to create streaming source element\n"); - break; - } - - debug_log("using streamming source [%s].\n", player->ini.name_of_rtspsrc); - - /* make it zero */ - network_bandwidth = 0; - user_agent = wap_profile = NULL; - - /* get attribute */ - mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent ); - mm_attrs_get_string_by_name ( attrs,"streaming_wap_profile", &wap_profile ); - mm_attrs_get_int_by_name ( attrs, "streaming_network_bandwidth", &network_bandwidth ); - - secure_debug_log("user_agent : %s\n", user_agent); - secure_debug_log("wap_profile : %s\n", wap_profile); - - /* setting property to streaming source */ - g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL); - if ( user_agent ) - g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL); - if ( wap_profile ) - g_object_set(G_OBJECT(element), "wap_profile", wap_profile, NULL); - - MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", - G_CALLBACK (__mmplayer_gst_rtp_dynamic_pad), player ); - MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", - G_CALLBACK (__mmplayer_gst_rtp_no_more_pads), player ); - - player->use_decodebin = FALSE; - } - break; -#if 0 - /* WFD streamming */ - case MM_PLAYER_URI_TYPE_URL_WFD: - { - element = gst_element_factory_make("wfdrtspsrc", "wfd_source"); - if ( !element ) - { - debug_error("failed to create wfd streaming source element\n"); - break; - } - debug_log("using wfd streamming source wfdrtspsrc.\n"); - g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL); - g_object_set(G_OBJECT(element), "debug", TRUE, NULL); - g_object_set(G_OBJECT(element), "latency", 0, NULL); - MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", - G_CALLBACK (__mmplayer_gst_wfd_dynamic_pad), player ); - - player->use_decodebin = FALSE; - } - break; -#endif - /* http streaming*/ - case MM_PLAYER_URI_TYPE_URL_HTTP: - { - gchar *user_agent, *proxy, *cookies, **cookie_list; - gint http_timeout = DEFAULT_HTTP_TIMEOUT; - user_agent = proxy = cookies = NULL; - cookie_list = NULL; - gint mode = MM_PLAYER_PD_MODE_NONE; - - mm_attrs_get_int_by_name ( attrs, "pd_mode", &mode ); - - player->pd_mode = mode; - - debug_log("http playback, PD mode : %d\n", player->pd_mode); - - if ( ! MMPLAYER_IS_HTTP_PD(player) ) - { - element = gst_element_factory_make(player->ini.name_of_httpsrc, "http_streaming_source"); - if ( !element ) - { - debug_error("failed to create http streaming source element[%s].\n", player->ini.name_of_httpsrc); - break; - } - debug_log("using http streamming source [%s].\n", player->ini.name_of_httpsrc); - - /* get attribute */ - mm_attrs_get_string_by_name ( attrs, "streaming_cookie", &cookies ); - mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent ); - mm_attrs_get_string_by_name ( attrs, "streaming_proxy", &proxy ); - mm_attrs_get_int_by_name ( attrs, "streaming_timeout", &http_timeout ); - - if ((http_timeout == DEFAULT_HTTP_TIMEOUT) && - (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) - { - debug_log("get timeout from ini\n"); - http_timeout = player->ini.http_timeout; - } - - /* get attribute */ - secure_debug_log("location : %s\n", player->profile.uri); - secure_debug_log("cookies : %s\n", cookies); - secure_debug_log("proxy : %s\n", proxy); - secure_debug_log("user_agent : %s\n", user_agent); - debug_log("timeout : %d\n", http_timeout); - - /* setting property to streaming source */ - g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL); - g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL); - g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL); - - /* check if prosy is vailid or not */ - if ( util_check_valid_url ( proxy ) ) - g_object_set(G_OBJECT(element), "proxy", proxy, NULL); - /* parsing cookies */ - if ( ( cookie_list = util_get_cookie_list ((const char*)cookies) ) ) - g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL); - if ( user_agent ) - g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL); - - if ( MMPLAYER_URL_HAS_DASH_SUFFIX(player) ) - { - debug_warning("it's dash. and it's still experimental feature."); - } - } - else // progressive download - { - gchar* location = NULL; - - if (player->pd_mode == MM_PLAYER_PD_MODE_URI) - { - gchar *path = NULL; - - mm_attrs_get_string_by_name ( attrs, "pd_location", &path ); - - MMPLAYER_FREEIF(player->pd_file_save_path); - - debug_log("PD Location : %s\n", path); - - if ( path ) - { - player->pd_file_save_path = g_strdup(path); - } - else - { - debug_error("can't find pd location so, it should be set \n"); - return MM_ERROR_PLAYER_FILE_NOT_FOUND; - } - } - - element = gst_element_factory_make("pdpushsrc", "PD pushsrc"); - if ( !element ) - { - debug_error("failed to create PD push source element[%s].\n", "pdpushsrc"); - break; - } - - if (player->pd_mode == MM_PLAYER_PD_MODE_URI) - g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL); - else - g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL); - - g_object_get(element, "location", &location, NULL); - debug_log("PD_LOCATION [%s].\n", location); - if (location) - g_free (location); - } - } - break; - - /* file source */ - case MM_PLAYER_URI_TYPE_FILE: - { - - debug_log("using filesrc for 'file://' handler.\n"); - - element = gst_element_factory_make("filesrc", "source"); - - if ( !element ) - { - debug_error("failed to create filesrc\n"); - break; - } - - g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */ - //g_object_set(G_OBJECT(element), "use-mmap", TRUE, NULL); - } - break; - - case MM_PLAYER_URI_TYPE_SS: - { - gint http_timeout = DEFAULT_HTTP_TIMEOUT; - element = gst_element_factory_make("souphttpsrc", "http streaming source"); - if ( !element ) - { - debug_error("failed to create http streaming source element[%s]", player->ini.name_of_httpsrc); - break; - } - - mm_attrs_get_int_by_name ( attrs, "streaming_timeout", &http_timeout ); - - if ((http_timeout == DEFAULT_HTTP_TIMEOUT) && - (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) - { - debug_log("get timeout from ini\n"); - http_timeout = player->ini.http_timeout; - } - - /* setting property to streaming source */ - g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL); - g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL); - } - break; - - /* appsrc */ - case MM_PLAYER_URI_TYPE_BUFF: - { - guint64 stream_type = GST_APP_STREAM_TYPE_STREAM; - - debug_log("mem src is selected\n"); - - element = gst_element_factory_make("appsrc", "buff-source"); - if ( !element ) - { - debug_error("failed to create appsrc element\n"); - break; - } - - g_object_set( element, "stream-type", stream_type, NULL ); - //g_object_set( element, "size", player->mem_buf.len, NULL ); - //g_object_set( element, "blocksize", (guint64)20480, NULL ); - - MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", - G_CALLBACK(__gst_appsrc_seek_data), player); - MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", - G_CALLBACK(__gst_appsrc_feed_data), player); - MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data", - G_CALLBACK(__gst_appsrc_enough_data), player); - } - break; - case MM_PLAYER_URI_TYPE_ES_BUFF: - { - debug_log("es buff src is selected\n"); - - if (player->v_stream_caps) - { - element = gst_element_factory_make("appsrc", "video_appsrc"); - if ( !element ) - { - debug_critical("failed to create video app source element[appsrc].\n" ); - break; - } - - if ( player->a_stream_caps ) - { - elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc"); - if ( !elem_src_audio ) - { - debug_critical("failed to create audio app source element[appsrc].\n" ); - break; - } - } - } - else if ( player->a_stream_caps ) - { - /* no video, only audio pipeline*/ - element = gst_element_factory_make("appsrc", "audio_appsrc"); - if ( !element ) - { - debug_critical("failed to create audio app source element[appsrc].\n" ); - break; - } - } - - if ( player->s_stream_caps ) - { - elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc"); - if ( !elem_src_subtitle ) - { - debug_critical("failed to create subtitle app source element[appsrc].\n" ); - break; - } - } - - debug_log("setting app sources properties.\n"); - debug_log("location : %s\n", player->profile.uri); - - if ( player->v_stream_caps && element ) - { - g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME, - "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */ - "caps", player->v_stream_caps, NULL); - - if ( player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0) - g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL); - if ( player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0) - g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL); - - /*Fix Seek External Demuxer: set audio and video appsrc as seekable */ - gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE); - MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", - G_CALLBACK(__gst_seek_video_data), player); - - if (player->a_stream_caps && elem_src_audio) - { - g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME, - "caps", player->a_stream_caps, NULL); - - if ( player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0) - g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL); - if ( player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0) - g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL); - - /*Fix Seek External Demuxer: set audio and video appsrc as seekable */ - gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE); - MMPLAYER_SIGNAL_CONNECT( player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", - G_CALLBACK(__gst_seek_audio_data), player); - } - } - else if (player->a_stream_caps && element) - { - g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME, - "caps", player->a_stream_caps, NULL); - - if ( player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0) - g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL); - if ( player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0) - g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL); - - /*Fix Seek External Demuxer: set audio and video appsrc as seekable */ - gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE); - MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", - G_CALLBACK(__gst_seek_audio_data), player); - } - - if (player->s_stream_caps && elem_src_subtitle) - { - g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME, - "caps", player->s_stream_caps, NULL); - - if ( player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0) - g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL); - if ( player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0) - g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL); - - gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE); - - MMPLAYER_SIGNAL_CONNECT( player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", - G_CALLBACK(__gst_seek_subtitle_data), player); - } - - if (!player->es_player_push_mode) - { - if (player->v_stream_caps && element) - { - MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", - G_CALLBACK(__gst_appsrc_feed_video_data), player); - MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data", - G_CALLBACK(__gst_appsrc_enough_video_data), player); - - if (player->a_stream_caps && elem_src_audio) - { - MMPLAYER_SIGNAL_CONNECT( player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", - G_CALLBACK(__gst_appsrc_feed_audio_data), player); - MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data", - G_CALLBACK(__gst_appsrc_enough_audio_data), player); - } - } - else if (player->a_stream_caps && element) - { - MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", - G_CALLBACK(__gst_appsrc_feed_audio_data), player); - MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data", - G_CALLBACK(__gst_appsrc_enough_audio_data), player); - } - - if (player->s_stream_caps && elem_src_subtitle) - { - MMPLAYER_SIGNAL_CONNECT( player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", - G_CALLBACK(__gst_appsrc_feed_subtitle_data), player); - } - } - - need_state_holder = FALSE; - } - break; - /* appsrc */ - case MM_PLAYER_URI_TYPE_MEM: - { - guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS; - - debug_log("mem src is selected\n"); - - element = gst_element_factory_make("appsrc", "mem-source"); - if ( !element ) - { - debug_error("failed to create appsrc element\n"); - break; - } - - g_object_set( element, "stream-type", stream_type, NULL ); - g_object_set( element, "size", player->mem_buf.len, NULL ); - g_object_set( element, "blocksize", (guint64)20480, NULL ); - - MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", - G_CALLBACK(__gst_appsrc_seek_data_mem), &player->mem_buf ); - MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", - G_CALLBACK(__gst_appsrc_feed_data_mem), &player->mem_buf ); - } - break; - case MM_PLAYER_URI_TYPE_URL: - break; - - case MM_PLAYER_URI_TYPE_TEMP: - break; - - case MM_PLAYER_URI_TYPE_NONE: - default: - break; - } - - /* check source element is OK */ - if ( ! element ) - { - debug_error("no source element was created.\n"); - goto INIT_ERROR; - } - - /* take source element */ - mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC; - mainbin[MMPLAYER_M_SRC].gst = element; - element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]); - - if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) - { - player->streamer = __mm_player_streaming_create(); - __mm_player_streaming_initialize(player->streamer); - } - - if ( MMPLAYER_IS_HTTP_PD(player) ) - { - gdouble pre_buffering_time = (gdouble)player->streamer->buffering_req.initial_second; - - debug_log ("Picked queue2 element(pre buffer : %d sec)....\n", pre_buffering_time); - element = gst_element_factory_make("queue2", "queue2"); - if ( !element ) - { - debug_error ( "failed to create http streaming buffer element\n" ); - goto INIT_ERROR; - } - - /* take it */ - mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER; - mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element; - element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]); - - pre_buffering_time = (pre_buffering_time > 0)?(pre_buffering_time):(player->ini.http_buffering_time); - - __mm_player_streaming_set_queue2(player->streamer, - element, - TRUE, - player->ini.http_max_size_bytes, - pre_buffering_time, - 1.0, - player->ini.http_buffering_limit, - FALSE, - NULL, - 0); - } - if (MMPLAYER_IS_ES_BUFF_SRC(player)) - { - if (player->v_stream_caps) - { - es_video_queue = gst_element_factory_make("queue2", "video_queue"); - if (!es_video_queue) - { - debug_error ("create es_video_queue for es player failed\n"); - goto INIT_ERROR; - } - mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER; - mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue; - element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]); - - /* Adding audio appsrc to bucket */ - if (player->a_stream_caps && elem_src_audio) - { - mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC; - mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio; - element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]); - - es_audio_queue = gst_element_factory_make("queue2", "audio_queue"); - if (!es_audio_queue) - { - debug_error ("create es_audio_queue for es player failed\n"); - goto INIT_ERROR; - } - mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER; - mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue; - element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]); - } - } - /* Only audio stream, no video */ - else if (player->a_stream_caps) - { - es_audio_queue = gst_element_factory_make("queue2", "audio_queue"); - if (!es_audio_queue) - { - debug_error ("create es_audio_queue for es player failed\n"); - goto INIT_ERROR; - } - mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER; - mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue; - element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]); - } - - if (player->s_stream_caps && elem_src_subtitle) - { - mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC; - mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle; - element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]); - - es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue"); - if (!es_subtitle_queue) - { - debug_error ("create es_subtitle_queue for es player failed\n"); - goto INIT_ERROR; - } - mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER; - mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue; - element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]); - } - } - - /* create autoplugging element if src element is not a rtsp src */ - if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) && - (player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_WFD) && - (player->profile.uri_type != MM_PLAYER_URI_TYPE_ES_BUFF)) - { - element = NULL; - enum MainElementID elemId = MMPLAYER_M_NUM; - - if ((player->use_decodebin) && - ((MMPLAYER_IS_HTTP_PD(player)) || - (!MMPLAYER_IS_HTTP_STREAMING(player)))) - { - elemId = MMPLAYER_M_AUTOPLUG; - element = __mmplayer_create_decodebin(player); - need_state_holder = FALSE; - } - else - { - elemId = MMPLAYER_M_TYPEFIND; - element = gst_element_factory_make("typefind", "typefinder"); - MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", - G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player ); - } - - - /* check autoplug element is OK */ - if ( ! element ) - { - debug_error("can not create element (%d)\n", elemId); - goto INIT_ERROR; - } - - mainbin[elemId].id = elemId; - mainbin[elemId].gst = element; - - element_bucket = g_list_append(element_bucket, &mainbin[elemId]); - } - - /* add elements to pipeline */ - if( !__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) - { - debug_error("Failed to add elements to pipeline\n"); - goto INIT_ERROR; - } - - - /* linking elements in the bucket by added order. */ - if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 ) - { - debug_error("Failed to link some elements\n"); - goto INIT_ERROR; - } - - - /* create fakesink element for keeping the pipeline state PAUSED. if needed */ - if ( need_state_holder ) - { - /* create */ - mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK; - mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make ("fakesink", "state-holder"); - - if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) - { - debug_error ("fakesink element could not be created\n"); - goto INIT_ERROR; - } - GST_OBJECT_FLAG_UNSET (mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK); - - /* take ownership of fakesink. we are reusing it */ - gst_object_ref( mainbin[MMPLAYER_M_SRC_FAKESINK].gst ); - - /* add */ - if ( FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), - mainbin[MMPLAYER_M_SRC_FAKESINK].gst) ) - { - debug_error("failed to add fakesink to bin\n"); - goto INIT_ERROR; - } - } - - /* now we have completed mainbin. take it */ - player->pipeline->mainbin = mainbin; - - if (MMPLAYER_IS_ES_BUFF_SRC(player)) - { - GstPad *srcpad = NULL; - - if (mainbin[MMPLAYER_M_V_BUFFER].gst) - { - srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src"); - if (srcpad) - { - __mmplayer_gst_create_decoder ( player, - MM_PLAYER_TRACK_TYPE_VIDEO, - srcpad, - MMPLAYER_M_AUTOPLUG_V_DEC, - "video_decodebin"); - - gst_object_unref ( GST_OBJECT(srcpad) ); - srcpad = NULL; - } - } - - if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) - { - srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src"); - if (srcpad) - { - __mmplayer_gst_create_decoder ( player, - MM_PLAYER_TRACK_TYPE_AUDIO, - srcpad, - MMPLAYER_M_AUTOPLUG_A_DEC, - "audio_decodebin"); - - gst_object_unref ( GST_OBJECT(srcpad) ); - srcpad = NULL; - } // else error - } // else error - - if (mainbin[MMPLAYER_M_S_BUFFER].gst) - { - __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps); - } - } - - /* connect bus callback */ - bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst)); - if ( !bus ) - { - debug_error ("cannot get bus from pipeline.\n"); - goto INIT_ERROR; - } - - player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player); - - player->context.thread_default = g_main_context_get_thread_default(); - - if (NULL == player->context.thread_default) - { - player->context.thread_default = g_main_context_default(); - debug_log("thread-default context is the global default context"); - } - debug_warning("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher); - - /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */ - if ( __mmplayer_check_subtitle ( player ) ) - { - if ( MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player) ) - debug_error("fail to create subtitle src\n"); - } - - /* set sync handler to get tag synchronously */ - gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL); - - /* finished */ - gst_object_unref(GST_OBJECT(bus)); - g_list_free(element_bucket); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; - -INIT_ERROR: - - __mmplayer_gst_destroy_pipeline(player); - g_list_free(element_bucket); - - /* release element which are not added to bin */ - for ( i = 1; i < MMPLAYER_M_NUM; i++ ) /* NOTE : skip pipeline */ - { - if ( mainbin[i].gst ) - { - GstObject* parent = NULL; - parent = gst_element_get_parent( mainbin[i].gst ); - - if ( !parent ) - { - gst_object_unref(GST_OBJECT(mainbin[i].gst)); - mainbin[i].gst = NULL; - } - else - { - gst_object_unref(GST_OBJECT(parent)); - } - } - } - - /* release pipeline with it's childs */ - if ( mainbin[MMPLAYER_M_PIPE].gst ) - { - gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst)); - } - - MMPLAYER_FREEIF( player->pipeline ); - MMPLAYER_FREEIF( mainbin ); - - return MM_ERROR_PLAYER_INTERNAL; -} - -void __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id) -{ - GSource *source = NULL; - - MMPLAYER_FENTER(); - - source = g_main_context_find_source_by_id (context, source_id); - - if (source != NULL) - { - debug_warning("context: %p, source id: %d, source: %p", context, source_id, source); - g_source_destroy(source); - } - - MMPLAYER_FLEAVE(); -} - -static void -__mmplayer_reset_gapless_state(mm_player_t* player) -{ - MMPLAYER_FENTER(); - return_if_fail(player - && player->pipeline - && player->pipeline->audiobin - && player->pipeline->audiobin[MMPLAYER_A_BIN].gst); - - if (player->gapless.audio_data_probe_id != 0) - { - GstPad *sinkpad; - sinkpad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_BIN].gst, "sink"); - gst_pad_remove_probe (sinkpad, player->gapless.audio_data_probe_id); - gst_object_unref (sinkpad); - } - memset(&player->gapless, 0, sizeof(mm_player_gapless_t)); - - MMPLAYER_FLEAVE(); - return; -} - -static int -__mmplayer_gst_destroy_pipeline(mm_player_t* player) // @ -{ - gint timeout = 0; - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_INVALID_HANDLE ); - - /* cleanup stuffs */ - MMPLAYER_FREEIF(player->type); - player->have_dynamic_pad = FALSE; - player->no_more_pad = FALSE; - player->num_dynamic_pad = 0; - player->demux_pad_index = 0; - player->subtitle_language_list = NULL; - player->use_deinterleave = FALSE; - player->max_audio_channels = 0; - player->video_share_api_delta = 0; - player->video_share_clock_delta = 0; - player->video_hub_download_mode = 0; - __mmplayer_reset_gapless_state(player); - __mmplayer_post_proc_reset(player); - - if (player->streamer) - { - __mm_player_streaming_deinitialize (player->streamer); - __mm_player_streaming_destroy(player->streamer); - player->streamer = NULL; - } - - /* cleanup unlinked mime type */ - MMPLAYER_FREEIF(player->unlinked_audio_mime); - MMPLAYER_FREEIF(player->unlinked_video_mime); - MMPLAYER_FREEIF(player->unlinked_demuxer_mime); - - /* cleanup running stuffs */ - __mmplayer_cancel_eos_timer( player ); -#if 0 //need to change and test - /* remove sound cb */ - if ( MM_ERROR_NONE != mm_sound_remove_device_information_changed_callback()) - { - debug_error("failed to mm_sound_remove_device_information_changed_callback()"); - } -#endif - /* cleanup gst stuffs */ - if ( player->pipeline ) - { - MMPlayerGstElement* mainbin = player->pipeline->mainbin; - GstTagList* tag_list = player->pipeline->tag_list; - - /* first we need to disconnect all signal hander */ - __mmplayer_release_signal_connection( player, MM_PLAYER_SIGNAL_TYPE_ALL ); - - /* disconnecting bus watch */ - if ( player->bus_watcher ) - __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher); - player->bus_watcher = 0; - - if ( mainbin ) - { - MMPlayerGstElement* audiobin = player->pipeline->audiobin; - MMPlayerGstElement* videobin = player->pipeline->videobin; - MMPlayerGstElement* textbin = player->pipeline->textbin; - GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (mainbin[MMPLAYER_M_PIPE].gst)); - gst_bus_set_sync_handler (bus, NULL, NULL, NULL); - gst_object_unref(bus); - - timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player); - ret = __mmplayer_gst_set_state ( player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout ); - if ( ret != MM_ERROR_NONE ) - { - debug_error("fail to change state to NULL\n"); - return MM_ERROR_PLAYER_INTERNAL; - } - - debug_warning("succeeded in chaning state to NULL\n"); - - gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst)); - - /* free fakesink */ - if ( mainbin[MMPLAYER_M_SRC_FAKESINK].gst ) - gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst)); - - /* free avsysaudiosink - avsysaudiosink should be unref when destory pipeline just after start play with BT. - Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed. - */ - MMPLAYER_FREEIF( audiobin ); - MMPLAYER_FREEIF( videobin ); - MMPLAYER_FREEIF( textbin ); - MMPLAYER_FREEIF( mainbin ); - } - - if ( tag_list ) - gst_tag_list_free(tag_list); - - MMPLAYER_FREEIF( player->pipeline ); - } - MMPLAYER_FREEIF(player->album_art); - - if (player->v_stream_caps) - { - gst_caps_unref(player->v_stream_caps); - player->v_stream_caps = NULL; - } - if (player->a_stream_caps) - { - gst_caps_unref(player->a_stream_caps); - player->a_stream_caps = NULL; - } - if (player->s_stream_caps) - { - gst_caps_unref(player->s_stream_caps); - player->s_stream_caps = NULL; - } - _mmplayer_track_destroy(player); - - if ( player->sink_elements ) - g_list_free ( player->sink_elements ); - player->sink_elements = NULL; - - debug_warning("finished destroy pipeline\n"); - - MMPLAYER_FLEAVE(); - - return ret; -} - -static int __gst_realize(mm_player_t* player) // @ -{ - gint timeout = 0; - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY; - - ret = __mmplayer_gst_create_pipeline(player); - if ( ret ) - { - debug_error("failed to create pipeline\n"); - return ret; - } - - /* set pipeline state to READY */ - /* NOTE : state change to READY must be performed sync. */ - timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player); - ret = __mmplayer_gst_set_state(player, - player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout); - - if ( ret != MM_ERROR_NONE ) - { - /* return error if failed to set state */ - debug_error("failed to set READY state"); - return ret; - } - else - { - MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_READY ); - } - - /* create dot before error-return. for debugging */ - MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-realize" ); - - MMPLAYER_FLEAVE(); - - return ret; -} - -static int __gst_unrealize(mm_player_t* player) // @ -{ - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL; - MMPLAYER_PRINT_STATE(player); - - /* release miscellaneous information */ - __mmplayer_release_misc( player ); - - /* destroy pipeline */ - ret = __mmplayer_gst_destroy_pipeline( player ); - if ( ret != MM_ERROR_NONE ) - { - debug_error("failed to destory pipeline\n"); - return ret; - } - - /* release miscellaneous information. - these info needs to be released after pipeline is destroyed. */ - __mmplayer_release_misc_post( player ); - - MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_NULL ); - - MMPLAYER_FLEAVE(); - - return ret; -} - -static int __gst_pending_seek ( mm_player_t* player ) -{ - MMPlayerStateType current_state = MM_PLAYER_STATE_NONE; - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - if ( !player->pending_seek.is_pending ) - { - debug_log("pending seek is not reserved. nothing to do.\n" ); - return ret; - } - - /* check player state if player could pending seek or not. */ - current_state = MMPLAYER_CURRENT_STATE(player); - - if ( current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING ) - { - debug_warning("try to pending seek in %s state, try next time. \n", - MMPLAYER_STATE_GET_NAME(current_state)); - return ret; - } - - debug_log("trying to play from (%lu) pending position\n", player->pending_seek.pos); - - ret = __gst_set_position ( player, player->pending_seek.format, player->pending_seek.pos, FALSE ); - - if ( MM_ERROR_NONE != ret ) - debug_error("failed to seek pending postion. just keep staying current position.\n"); - - player->pending_seek.is_pending = FALSE; - - MMPLAYER_FLEAVE(); - - return ret; -} - -static int __gst_start(mm_player_t* player) // @ -{ - gboolean sound_extraction = 0; - int ret = MM_ERROR_NONE; - gboolean async = FALSE; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - /* get sound_extraction property */ - mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction); - - /* NOTE : if SetPosition was called before Start. do it now */ - /* streaming doesn't support it. so it should be always sync */ - /* !! create one more api to check if there is pending seek rather than checking variables */ - if ( (player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) - { - MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED; - ret = __gst_pause(player, FALSE); - if ( ret != MM_ERROR_NONE ) - { - debug_error("failed to set state to PAUSED for pending seek\n"); - return ret; - } - - MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING; - - if ( sound_extraction ) - { - debug_log("setting pcm extraction\n"); - - ret = __mmplayer_set_pcm_extraction(player); - if ( MM_ERROR_NONE != ret ) - { - debug_warning("failed to set pcm extraction\n"); - return ret; - } - } - else - { - if ( MM_ERROR_NONE != __gst_pending_seek(player) ) - { - debug_warning("failed to seek pending postion. starting from the begin of content.\n"); - } - } - } - - debug_log("current state before doing transition"); - MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING; - MMPLAYER_PRINT_STATE(player); - - /* set pipeline state to PLAYING */ - if (player->es_player_push_mode) - { - async = TRUE; - } - /* set pipeline state to PLAYING */ - ret = __mmplayer_gst_set_state(player, - player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player) ); - - if (ret == MM_ERROR_NONE) - { - MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING); - } - else - { - debug_error("failed to set state to PLAYING"); - return ret; - } - - /* generating debug info before returning error */ - MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-start" ); - - MMPLAYER_FLEAVE(); - - return ret; -} - -static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time) -{ - MMPLAYER_FENTER(); - - return_if_fail(player - && player->pipeline - && player->pipeline->audiobin - && player->pipeline->audiobin[MMPLAYER_A_SINK].gst); - - g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 2, NULL); - - usleep(time); - - MMPLAYER_FLEAVE(); -} - -static void __mmplayer_undo_sound_fadedown(mm_player_t* player) -{ - MMPLAYER_FENTER(); - - return_if_fail(player - && player->pipeline - && player->pipeline->audiobin - && player->pipeline->audiobin[MMPLAYER_A_SINK].gst); - - g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL); - - MMPLAYER_FLEAVE(); -} - -static int __gst_stop(mm_player_t* player) // @ -{ - GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS; - MMHandleType attrs = 0; - gboolean fadedown = FALSE; - gboolean rewind = FALSE; - gint timeout = 0; - int ret = MM_ERROR_NONE; - GstState state; - gboolean async = FALSE; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail ( player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED); - - debug_log("current state before doing transition"); - MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY; - MMPLAYER_PRINT_STATE(player); - - attrs = MMPLAYER_GET_ATTRS(player); - if ( !attrs ) - { - debug_error("cannot get content attribute\n"); - return MM_ERROR_PLAYER_INTERNAL; - } - - mm_attrs_get_int_by_name(attrs, "sound_fadedown", &fadedown); - - /* enable fadedown */ - if (fadedown || player->sound_focus.by_asm_cb) - __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT); - - /* Just set state to PAUESED and the rewind. it's usual player behavior. */ - timeout = MMPLAYER_STATE_CHANGE_TIMEOUT ( player ); - - if (player->profile.uri_type == MM_PLAYER_URI_TYPE_BUFF || - player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS) - { - state = GST_STATE_READY; - } - else - { - state = GST_STATE_PAUSED; - - if ( ! MMPLAYER_IS_STREAMING(player) || - (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked)) { - rewind = TRUE; - } - } - - if (player->es_player_push_mode) - { - async = TRUE; - } - /* set gst state */ - ret = __mmplayer_gst_set_state( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, state, async, timeout ); - - /* disable fadeout */ - if (fadedown || player->sound_focus.by_asm_cb) - __mmplayer_undo_sound_fadedown(player); - - /* return if set_state has failed */ - if ( ret != MM_ERROR_NONE ) - { - debug_error("failed to set state.\n"); - return ret; - } - - /* rewind */ - if ( rewind ) - { - if ( ! __gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate, - GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0, - GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE) ) - { - debug_warning("failed to rewind\n"); - ret = MM_ERROR_PLAYER_SEEK; - } - } - - /* initialize */ - player->sent_bos = FALSE; - - if (player->es_player_push_mode) //for cloudgame - { - timeout = 0; - } - - /* wait for seek to complete */ - change_ret = gst_element_get_state (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND); - if ( change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL ) - { - MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_READY ); - } - else - { - debug_error("fail to stop player.\n"); - ret = MM_ERROR_PLAYER_INTERNAL; - __mmplayer_dump_pipeline_state(player); - } - - /* generate dot file if enabled */ - MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-stop" ); - - MMPLAYER_FLEAVE(); - - return ret; -} - -int __gst_pause(mm_player_t* player, gboolean async) // @ -{ - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED); - - debug_log("current state before doing transition"); - MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED; - MMPLAYER_PRINT_STATE(player); - - /* set pipeline status to PAUSED */ - player->ignore_asyncdone = TRUE; - - ret = __mmplayer_gst_set_state(player, - player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player)); - - player->ignore_asyncdone = FALSE; - - if ( FALSE == async ) - { - if ( ret != MM_ERROR_NONE ) - { - GstMessage *msg = NULL; - GTimer *timer = NULL; - gdouble MAX_TIMEOUT_SEC = 3; - - debug_error("failed to set state to PAUSED"); - - timer = g_timer_new(); - g_timer_start(timer); - - GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)); - gboolean got_msg = FALSE; - /* check if gst error posted or not */ - do - { - msg = gst_bus_timed_pop(bus, GST_SECOND /2); - if (msg) - { - if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) - { - GError *error = NULL; - - /* parse error code */ - gst_message_parse_error(msg, &error, NULL); - - if ( gst_structure_has_name ( gst_message_get_structure(msg), "streaming_error" ) ) - { - /* Note : the streaming error from the streaming source is handled - * using __mmplayer_handle_streaming_error. - */ - __mmplayer_handle_streaming_error ( player, msg ); - - } - else if (error) - { - debug_error("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code); - - if (error->domain == GST_STREAM_ERROR) - { - ret = __gst_handle_stream_error( player, error, msg ); - } - else if (error->domain == GST_RESOURCE_ERROR) - { - ret = __gst_handle_resource_error( player, error->code ); - } - else if (error->domain == GST_LIBRARY_ERROR) - { - ret = __gst_handle_library_error( player, error->code ); - } - else if (error->domain == GST_CORE_ERROR) - { - ret = __gst_handle_core_error( player, error->code ); - } - } - - got_msg = TRUE; - player->msg_posted = TRUE; - } - gst_message_unref(msg); - } - } while (!got_msg && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC)); - /* clean */ - gst_object_unref(bus); - g_timer_stop (timer); - g_timer_destroy (timer); - - return ret; - } - else if ( (!player->pipeline->videobin) && (!player->pipeline->audiobin) ) - { - if (MMPLAYER_IS_RTSP_STREAMING(player)) - return ret; - return MM_ERROR_PLAYER_CODEC_NOT_FOUND; - } - else if ( ret== MM_ERROR_NONE) - { - MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PAUSED ); - } - } - - /* generate dot file before returning error */ - MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-pause" ); - - MMPLAYER_FLEAVE(); - - return ret; -} - -int __gst_resume(mm_player_t* player, gboolean async) // @ -{ - int ret = MM_ERROR_NONE; - gint timeout = 0; - - MMPLAYER_FENTER(); - - return_val_if_fail(player && player->pipeline, - MM_ERROR_PLAYER_NOT_INITIALIZED); - - debug_log("current state before doing transition"); - MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING; - MMPLAYER_PRINT_STATE(player); - - /* generate dot file before returning error */ - MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-resume" ); - - if ( async ) - debug_log("do async state transition to PLAYING.\n"); - - /* set pipeline state to PLAYING */ - timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player); - - ret = __mmplayer_gst_set_state(player, - player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout ); - if (ret != MM_ERROR_NONE) - { - debug_error("failed to set state to PLAYING\n"); - return ret; - } - else - { - if (async == FALSE) - { - // MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PLAYING ); - debug_log("update state machine to %d\n", MM_PLAYER_STATE_PLAYING); - ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING); - } - } - - /* generate dot file before returning error */ - MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-resume" ); - - MMPLAYER_FLEAVE(); - - return ret; -} - -static int -__gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called) // @ -{ - unsigned long dur_msec = 0; - gint64 dur_nsec = 0; - gint64 pos_nsec = 0; - gboolean ret = TRUE; - gboolean accurated = FALSE; - GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH; - - MMPLAYER_FENTER(); - return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED ); - return_val_if_fail ( !MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP ); - - if ( MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING - && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED ) - goto PENDING; - - if( !MMPLAYER_IS_ES_BUFF_SRC(player) ) - { - /* check duration */ - /* NOTE : duration cannot be zero except live streaming. - * Since some element could have some timing problemn with quering duration, try again. - */ - if ( !player->duration ) - { - if ( !gst_element_query_duration( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec )) - { - goto SEEK_ERROR; - } - player->duration = dur_nsec; - } - - if ( player->duration ) - { - dur_msec = GST_TIME_AS_MSECONDS(player->duration); - } - else - { - debug_error("could not get the duration. fail to seek.\n"); - goto SEEK_ERROR; - } - } - debug_log("playback rate: %f\n", player->playback_rate); - - mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated); - if (accurated) - { - seek_flags |= GST_SEEK_FLAG_ACCURATE; - } - else - { - seek_flags |= GST_SEEK_FLAG_KEY_UNIT; - } - - /* do seek */ - switch ( format ) - { - case MM_PLAYER_POS_FORMAT_TIME: - { - if( !MMPLAYER_IS_ES_BUFF_SRC(player) ) - { - /* check position is valid or not */ - if ( position > dur_msec ) - goto INVALID_ARGS; - - debug_log("seeking to (%lu) msec, duration is %d msec\n", position, dur_msec); - - if ( player->doing_seek ) - { - debug_log("not completed seek"); - return MM_ERROR_PLAYER_DOING_SEEK; - } - } - - if ( !internal_called ) - player->doing_seek = TRUE; - - pos_nsec = position * G_GINT64_CONSTANT(1000000); - - if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) - { - gint64 cur_time = 0; - - /* get current position */ - gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time); - - /* flush */ - GstEvent *event = gst_event_new_seek (1.0, - GST_FORMAT_TIME, - (GstSeekFlags)GST_SEEK_FLAG_FLUSH, - GST_SEEK_TYPE_SET, cur_time, - GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); - if(event) { - __gst_send_event_to_sink(player, event); - } - - __gst_pause( player, FALSE ); - } - - ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate, - GST_FORMAT_TIME, seek_flags, - GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE ); - if ( !ret ) - { - debug_error("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec); - goto SEEK_ERROR; - } - } - break; - - case MM_PLAYER_POS_FORMAT_PERCENT: - { - debug_log("seeking to (%lu)%% \n", position); - - if (player->doing_seek) - { - debug_log("not completed seek"); - return MM_ERROR_PLAYER_DOING_SEEK; - } - - if ( !internal_called) - player->doing_seek = TRUE; - - /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */ - pos_nsec = (gint64) ( ( position * player->duration ) / 100 ); - ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate, - GST_FORMAT_TIME, seek_flags, - GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE ); - if ( !ret ) - { - debug_error("failed to set position. dur[%lud] pos[%lud] pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec); - goto SEEK_ERROR; - } - } - break; - - default: - goto INVALID_ARGS; - - } - - /* NOTE : store last seeking point to overcome some bad operation - * ( returning zero when getting current position ) of some elements - */ - player->last_position = pos_nsec; - - /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */ - if ( player->playback_rate > 1.0 ) - _mmplayer_set_playspeed ( (MMHandleType)player, player->playback_rate ); - - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; - -PENDING: - player->pending_seek.is_pending = TRUE; - player->pending_seek.format = format; - player->pending_seek.pos = position; - - debug_warning("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n", - MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos); - - return MM_ERROR_NONE; - -INVALID_ARGS: - debug_error("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format); - return MM_ERROR_INVALID_ARGUMENT; - -SEEK_ERROR: - player->doing_seek = FALSE; - return MM_ERROR_PLAYER_SEEK; -} - -#define TRICKPLAY_OFFSET GST_MSECOND - -static int -__gst_get_position(mm_player_t* player, int format, unsigned long* position) // @ -{ - MMPlayerStateType current_state = MM_PLAYER_STATE_NONE; - gint64 pos_msec = 0; - gboolean ret = TRUE; - - return_val_if_fail( player && position && player->pipeline && player->pipeline->mainbin, - MM_ERROR_PLAYER_NOT_INITIALIZED ); - - current_state = MMPLAYER_CURRENT_STATE(player); - - /* NOTE : query position except paused state to overcome some bad operation - * please refer to below comments in details - */ - if ( current_state != MM_PLAYER_STATE_PAUSED ) - { - ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec); - } - - /* NOTE : get last point to overcome some bad operation of some elements - * ( returning zero when getting current position in paused state - * and when failed to get postion during seeking - */ - if ( ( current_state == MM_PLAYER_STATE_PAUSED ) - || ( ! ret )) - //|| ( player->last_position != 0 && pos_msec == 0 ) ) - { - debug_log ("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS (pos_msec), ret, current_state); - - if(player->playback_rate < 0.0) - pos_msec = player->last_position - TRICKPLAY_OFFSET; - else - pos_msec = player->last_position; - - if (!ret) - pos_msec = player->last_position; - else - player->last_position = pos_msec; - - debug_log("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec)); - - } - else - { - if (player->duration > 0 && pos_msec > player->duration) { - pos_msec = player->duration; - } - - if (player->sound_focus.keep_last_pos) { - debug_log("return last pos as stop by asm, %"GST_TIME_FORMAT, GST_TIME_ARGS(player->last_position)); - pos_msec = player->last_position; - } - else { - player->last_position = pos_msec; - } - } - - switch (format) { - case MM_PLAYER_POS_FORMAT_TIME: - *position = GST_TIME_AS_MSECONDS(pos_msec); - break; - - case MM_PLAYER_POS_FORMAT_PERCENT: - { - gint64 dur = 0; - gint64 pos = 0; - - dur = player->duration / GST_SECOND; - if (dur <= 0) - { - debug_log ("duration is [%d], so returning position 0\n",dur); - *position = 0; - } - else - { - pos = pos_msec / GST_SECOND; - *position = pos * 100 / dur; - } - break; - } - default: - return MM_ERROR_PLAYER_INTERNAL; - } - - return MM_ERROR_NONE; -} - - -static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos) -{ -#define STREAMING_IS_FINISHED 0 -#define BUFFERING_MAX_PER 100 - - GstQuery *query = NULL; - - return_val_if_fail( player && - player->pipeline && - player->pipeline->mainbin, - MM_ERROR_PLAYER_NOT_INITIALIZED ); - - return_val_if_fail( start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT ); - - if (!MMPLAYER_IS_HTTP_STREAMING ( player )) - { - /* and rtsp is not ready yet. */ - debug_warning ( "it's only used for http streaming case.\n" ); - return MM_ERROR_NONE; - } - - *start_pos = 0; - *stop_pos = 0; - - switch ( format ) - { - case MM_PLAYER_POS_FORMAT_PERCENT : - { - gint start_per = -1, stop_per = -1; - gint64 buffered_total = 0; - - unsigned long position = 0; - guint curr_size_bytes = 0; - gint64 buffering_left = -1; - gint buffered_sec = -1; - - gint64 content_duration = player->duration; - guint64 content_size = player->http_content_size; - - if (content_duration > 0) - { - if (!__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) - { - debug_log ("[Time] pos %d ms / dur %d sec / %lld bytes", position, (guint)(content_duration/GST_SECOND), content_size); - start_per = 100 * (position*GST_MSECOND) / content_duration; - - /* buffered size info from multiqueue */ - if (player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) - { - g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst), "curr-size-bytes", &curr_size_bytes, NULL); - debug_log ("[MQ] curr_size_bytes = %d", curr_size_bytes); - - buffered_total += curr_size_bytes; - } - - /* buffered size info from queue2 */ - if (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) - { - query = gst_query_new_buffering ( GST_FORMAT_BYTES ); - if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) - { - GstBufferingMode mode; - gint byte_in_rate = 0, byte_out_rate = 0; - gint64 start_byte = 0, stop_byte = 0; - guint num_of_ranges = 0; - guint idx = 0; - - num_of_ranges = gst_query_get_n_buffering_ranges(query); - for ( idx=0 ; idx0)?((guint)(content_size/dur_sec)):(0); - - if (avg_byterate > 0) - buffered_sec = (gint)(buffered_total/avg_byterate); - else if (player->total_maximum_bitrate > 0) - buffered_sec = (gint)(GET_BIT_FROM_BYTE(buffered_total)/(gint64)player->total_maximum_bitrate); - else if (player->total_bitrate > 0) - buffered_sec = (gint)(GET_BIT_FROM_BYTE(buffered_total)/(gint64)player->total_bitrate); - - if ((buffered_sec >= 0) && (dur_sec > 0)) - stop_per = start_per + (100 * buffered_sec / dur_sec); - } - - debug_log ("[Buffered Total] %lld bytes, %d sec, per %d~%d\n", buffered_total, buffered_sec, start_per, stop_per); - } - } - - if (((buffered_total == 0) || (start_per < 0) || (stop_per < 0)) && - (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) - { - query = gst_query_new_buffering ( GST_FORMAT_PERCENT ); - if ( gst_element_query ( player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query ) ) - { - GstFormat format; - gint64 range_start_per = -1, range_stop_per = -1; - - gst_query_parse_buffering_range ( query, &format, &range_start_per, &range_stop_per, NULL ); - - debug_log ("[Q2] range start %" G_GINT64_FORMAT " ~ stop %" G_GINT64_FORMAT "\n", range_start_per , range_stop_per); - - if (range_start_per != -1) - start_per = (gint)(100 * range_start_per / GST_FORMAT_PERCENT_MAX); - - if (range_stop_per != -1) - stop_per = (gint)(100 * range_stop_per / GST_FORMAT_PERCENT_MAX); - } - gst_query_unref (query); - } - - if ( start_per > 0) - *start_pos = (start_per < 100)?(start_per):(100); - else - *start_pos = 0; - - if ( stop_per > 0) - *stop_pos = (stop_per < 100)?(stop_per):(100); - else - *stop_pos = 0; - - break; - } - case MM_PLAYER_POS_FORMAT_TIME : - debug_warning ( "Time format is not supported yet.\n" ); - break; - - default : - break; - } - - debug_log("current buffer position : %lu~%lu \n", *start_pos, *stop_pos ); - - return MM_ERROR_NONE; -} - -static int -__gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param) // @ -{ - MMPLAYER_FENTER(); - - if ( !player ) - { - debug_warning("set_message_callback is called with invalid player handle\n"); - return MM_ERROR_PLAYER_NOT_INITIALIZED; - } - - player->msg_cb = callback; - player->msg_cb_param = user_param; - - debug_log("msg_cb : %p msg_cb_param : %p\n", callback, user_param); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data) // @ -{ - int ret = MM_ERROR_PLAYER_INVALID_URI; - char *path = NULL; - - MMPLAYER_FENTER(); - - return_val_if_fail ( uri , FALSE); - return_val_if_fail ( data , FALSE); - return_val_if_fail ( ( strlen(uri) <= MM_MAX_URL_LEN ), FALSE ); - - memset(data, 0, sizeof(MMPlayerParseProfile)); - - if ((path = strstr(uri, "file://"))) - { - int file_stat = MM_ERROR_NONE; - - file_stat = util_exist_file_path(path + 7); - - if (file_stat == MM_ERROR_NONE) - { - strncpy(data->uri, path, MM_MAX_URL_LEN-1); - - if ( util_is_sdp_file ( path ) ) - { - debug_log("uri is actually a file but it's sdp file. giving it to rtspsrc\n"); - data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP; - } - else - { - data->uri_type = MM_PLAYER_URI_TYPE_FILE; - } - ret = MM_ERROR_NONE; - } - else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) - { - data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION; - } - else - { - debug_warning("could access %s.\n", path); - } - } - else if ((path = strstr(uri, "es_buff://"))) - { - if (strlen(path)) - { - strcpy(data->uri, uri); - data->uri_type = MM_PLAYER_URI_TYPE_ES_BUFF; - ret = MM_ERROR_NONE; - } - } - else if ((path = strstr(uri, "buff://"))) - { - data->uri_type = MM_PLAYER_URI_TYPE_BUFF; - ret = MM_ERROR_NONE; - } - else if ((path = strstr(uri, "rtsp://"))) - { - if (strlen(path)) { - if((path = strstr(uri, "/wfd1.0/"))) { - strcpy(data->uri, uri); - data->uri_type = MM_PLAYER_URI_TYPE_URL_WFD; - ret = MM_ERROR_NONE; - debug_log("uri is actually a wfd client path. giving it to wfdrtspsrc\n"); - } - else { - strcpy(data->uri, uri); - data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP; - ret = MM_ERROR_NONE; - } - } - } - else if ((path = strstr(uri, "http://"))) - { - if (strlen(path)) { - strcpy(data->uri, uri); -#ifdef MM_SMOOTH_STREAMING - if (g_str_has_suffix (g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") || - g_str_has_suffix (g_ascii_strdown(uri, strlen(uri)), ".isml/manifest")) - { - data->uri_type = MM_PLAYER_URI_TYPE_SS; - } - else -#endif - data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP; - - ret = MM_ERROR_NONE; - } - } - else if ((path = strstr(uri, "https://"))) - { - if (strlen(path)) { - strcpy(data->uri, uri); -#ifdef MM_SMOOTH_STREAMING - if (g_str_has_suffix (g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") || - g_str_has_suffix (g_ascii_strdown(uri, strlen(uri)), ".isml/manifest")) - { - data->uri_type = MM_PLAYER_URI_TYPE_SS; - } -#endif - data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP; - - ret = MM_ERROR_NONE; - } - } - else if ((path = strstr(uri, "rtspu://"))) - { - if (strlen(path)) { - strcpy(data->uri, uri); - data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP; - ret = MM_ERROR_NONE; - } - } - else if ((path = strstr(uri, "rtspr://"))) - { - strcpy(data->uri, path); - char *separater =strstr(path, "*"); - - if (separater) { - int urgent_len = 0; - char *urgent = separater + strlen("*"); - - if ((urgent_len = strlen(urgent))) { - data->uri[strlen(path) - urgent_len - strlen("*")] = '\0'; - strcpy(data->urgent, urgent); - data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP; - ret = MM_ERROR_NONE; - } - } - } - else if ((path = strstr(uri, "mms://"))) - { - if (strlen(path)) { - strcpy(data->uri, uri); - data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS; - ret = MM_ERROR_NONE; - } - } - else if ((path = strstr(uri, "mem://"))) - { - if (strlen(path)) { - int mem_size = 0; - char *buffer = NULL; - char *seperator = strchr(path, ','); - char ext[100] = {0,}, size[100] = {0,}; - - if (seperator) { - if ((buffer = strstr(path, "ext="))) { - buffer += strlen("ext="); - - if (strlen(buffer)) { - strcpy(ext, buffer); - - if ((seperator = strchr(ext, ',')) - || (seperator = strchr(ext, ' ')) - || (seperator = strchr(ext, '\0'))) { - seperator[0] = '\0'; - } - } - } - - if ((buffer = strstr(path, "size="))) { - buffer += strlen("size="); - - if (strlen(buffer) > 0) { - strcpy(size, buffer); - - if ((seperator = strchr(size, ',')) - || (seperator = strchr(size, ' ')) - || (seperator = strchr(size, '\0'))) { - seperator[0] = '\0'; - } - - mem_size = atoi(size); - } - } - } - - debug_log("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param); - if ( mem_size && param) - { - data->mem = param; - data->mem_size = mem_size; - data->uri_type = MM_PLAYER_URI_TYPE_MEM; - ret = MM_ERROR_NONE; - } - } - } - else - { - int file_stat = MM_ERROR_NONE; - - file_stat = util_exist_file_path(uri); - - /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */ - if (file_stat == MM_ERROR_NONE) - { - g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", uri); - - if ( util_is_sdp_file( (char*)uri ) ) - { - debug_log("uri is actually a file but it's sdp file. giving it to rtspsrc\n"); - data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP; - } - else - { - data->uri_type = MM_PLAYER_URI_TYPE_FILE; - } - ret = MM_ERROR_NONE; - } - else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) - { - data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION; - } - else - { - debug_error ("invalid uri, could not play..\n"); - data->uri_type = MM_PLAYER_URI_TYPE_NONE; - } - } - - if (data->uri_type == MM_PLAYER_URI_TYPE_NONE) { - ret = MM_ERROR_PLAYER_FILE_NOT_FOUND; - } else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION){ - ret = MM_ERROR_PLAYER_PERMISSION_DENIED; - } - - /* dump parse result */ - secure_debug_warning("incomming uri : %s\n", uri); - debug_log("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n", - data->uri_type, data->mem, data->mem_size, data->urgent); - - MMPLAYER_FLEAVE(); - - return ret; -} - -gboolean _asm_postmsg(gpointer *data) -{ - mm_player_t* player = (mm_player_t*)data; - MMMessageParamType msg = {0, }; - - MMPLAYER_FENTER(); - return_val_if_fail ( player, FALSE ); - debug_warning("get notified"); - - if ((player->cmd == MMPLAYER_COMMAND_DESTROY) || - (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) - { - debug_warning("dispatched"); - return FALSE; - } - - - msg.union_type = MM_MSG_UNION_CODE; - msg.code = player->sound_focus.focus_changed_msg; - -#if 0 // should remove - if (player->sm.event_src == ASM_EVENT_SOURCE_RESUMABLE_CANCELED) - { - /* fill the message with state of player */ - msg.state.current = MMPLAYER_CURRENT_STATE(player); - MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg); - player->resumable_cancel_id = 0; - } - else -#endif - { - MMPLAYER_POST_MSG( player, MM_MESSAGE_READY_TO_RESUME, &msg); - player->resume_event_id = 0; - } - - debug_warning("dispatched"); - return FALSE; -} - -gboolean _asm_lazy_pause(gpointer *data) -{ - mm_player_t* player = (mm_player_t*)data; - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, FALSE ); - - if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING) - { - debug_log ("Ready to proceed lazy pause\n"); - ret = _mmplayer_pause((MMHandleType)player); - if(MM_ERROR_NONE != ret) - { - debug_error("MMPlayer pause failed in ASM callback lazy pause\n"); - } - } - else - { - debug_log ("Invalid state to proceed lazy pause\n"); - } - - /* unset mute */ - if (player->pipeline && player->pipeline->audiobin) - g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL); - - player->sound_focus.by_asm_cb = FALSE; //should be reset here - - MMPLAYER_FLEAVE(); - - return FALSE; -} - -static gboolean -__mmplayer_can_do_interrupt(mm_player_t *player) -{ - if (!player || !player->pipeline || !player->attrs) - { - debug_warning("not initialized"); - goto FAILED; - } - - if ((player->sound_focus.exit_cb) || (player->set_mode.pcm_extraction)) - { - debug_warning("leave from asm cb right now, %d, %d", player->sound_focus.exit_cb, player->set_mode.pcm_extraction); - goto FAILED; - } - - /* check if seeking */ - if (player->doing_seek) - { - MMMessageParamType msg_param; - memset (&msg_param, 0, sizeof(MMMessageParamType)); - msg_param.code = MM_ERROR_PLAYER_SEEK; - player->doing_seek = FALSE; - MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param); - goto FAILED; - } - - /* check other thread */ - if (!g_mutex_trylock(&player->cmd_lock)) - { - debug_warning("locked already, cmd state : %d", player->cmd); - - /* check application command */ - if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) - { - debug_warning("playing.. should wait cmd lock then, will be interrupted"); - g_mutex_lock(&player->cmd_lock); - goto INTERRUPT; - } - debug_warning("nothing to do"); - goto FAILED; - } - else - { - debug_warning("can interrupt immediately"); - goto INTERRUPT; - } - -FAILED: - return FALSE; - -INTERRUPT: - return TRUE; -} - -/* if you want to enable USE_ASM, please check the history get the ASM cb code. */ -static int -__mmplayer_convert_sound_focus_state(gboolean acquire, const char *reason_for_change, MMPlayerFocusChangedMsg *msg) -{ - int ret = MM_ERROR_NONE; - MMPlayerFocusChangedMsg focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN; - - if (strstr(reason_for_change, "alarm")) { - focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_ALARM; - - } else if (strstr(reason_for_change, "notification")) { - focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_NOTIFICATION; - - } else if (strstr(reason_for_change, "emergency")) { - focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_EMERGENCY; - - } else if (strstr(reason_for_change, "call-voice") || - strstr(reason_for_change, "call-video") || - strstr(reason_for_change, "voip") || - strstr(reason_for_change, "ringtone-voip") || - strstr(reason_for_change, "ringtone-call")) { - focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_CALL; - - } else if (strstr(reason_for_change, "media") || - strstr(reason_for_change, "radio") || - strstr(reason_for_change, "loopback") || - strstr(reason_for_change, "system") || - strstr(reason_for_change, "voice-information") || - strstr(reason_for_change, "voice-recognition")) { - focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_MEDIA; - - } else { - ret = MM_ERROR_INVALID_ARGUMENT; - debug_warning("not supported reason(%s), err(0x%08x)", reason_for_change, ret); - goto DONE; - } - - if (acquire && (focus_msg != MM_PLAYER_FOCUS_CHANGED_BY_MEDIA)) - { - /* can acqurie */ - focus_msg = MM_PLAYER_FOCUS_CHANGED_COMPLETED; - } - - debug_log("converted from reason(%s) to msg(%d)", reason_for_change, focus_msg); - *msg = focus_msg; - -DONE: - return ret; -} - -/* FIXME: will be updated with new funct */ -void __mmplayer_sound_focus_watch_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state, - const char *reason_for_change, const char *additional_info, void *user_data) -{ - mm_player_t* player = (mm_player_t*) user_data; - int result = MM_ERROR_NONE; - MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN; - - debug_warning("focus watch notified"); - - if (!__mmplayer_can_do_interrupt(player)) - { - debug_warning("no need to interrupt, so leave"); - goto EXIT; - } - - if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) - { - debug_warning("flags is UNINTERRUPTIBLE. do nothing."); - goto EXIT; - } - - debug_warning("watch: state: %d, focus_type : %d, reason_for_change : %s", - focus_state, focus_type, (reason_for_change?reason_for_change:"N/A")); - - player->sound_focus.cb_pending = TRUE; - player->sound_focus.by_asm_cb = TRUE; - - if (focus_state == FOCUS_IS_ACQUIRED) - { - debug_warning("watch: FOCUS_IS_ACQUIRED"); - if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg)) - { - player->sound_focus.focus_changed_msg = (int)msg; - } - - if (strstr(reason_for_change, "call") || - strstr(reason_for_change, "voip") || /* FIXME: to check */ - strstr(reason_for_change, "alarm") || - strstr(reason_for_change, "media")) - { - if (!MMPLAYER_IS_RTSP_STREAMING(player)) - { - // hold 0.7 second to excute "fadedown mute" effect - debug_warning ("do fade down->pause->undo fade down"); - - __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT); - - result = _mmplayer_pause((MMHandleType)player); - if (result != MM_ERROR_NONE) - { - debug_warning("fail to set Pause state by asm"); - goto EXIT; - } - __mmplayer_undo_sound_fadedown(player); - } - else - { - /* rtsp should connect again in specific network becasue tcp session can't be kept any more */ - _mmplayer_unrealize((MMHandleType)player); - } - } - else - { - debug_warning ("pause immediately"); - result = _mmplayer_pause((MMHandleType)player); - if (result != MM_ERROR_NONE) - { - debug_warning("fail to set Pause state by asm"); - goto EXIT; - } - } - } - else if (focus_state == FOCUS_IS_RELEASED) - { - debug_warning("FOCUS_IS_RELEASED: Got msg from asm to resume"); - player->sound_focus.antishock = TRUE; - player->sound_focus.by_asm_cb = FALSE; - - if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg)) - { - player->sound_focus.focus_changed_msg = (int)msg; - } - - //ASM server is single thread daemon. So use g_idle_add() to post resume msg - player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player); - goto DONE; - } - else - { - debug_warning("unknown focus state %d", focus_state); - } - -DONE: - player->sound_focus.by_asm_cb = FALSE; - player->sound_focus.cb_pending = FALSE; - MMPLAYER_CMD_UNLOCK( player ); - -EXIT: - debug_warning("dispatched"); - return; -} - -void -__mmplayer_sound_focus_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state, - const char *reason_for_change, const char *additional_info, void *user_data) -{ - mm_player_t* player = (mm_player_t*) user_data; - int result = MM_ERROR_NONE; - gboolean lazy_pause = FALSE; - MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN; - - debug_warning("get focus notified"); - - if (!__mmplayer_can_do_interrupt(player)) - { - debug_warning("no need to interrupt, so leave"); - goto EXIT; - } - - if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) - { - debug_warning("flags is UNINTERRUPTIBLE. do nothing."); - goto EXIT; - } - - debug_warning("state: %d, focus_type : %d, reason_for_change : %s", - focus_state, focus_type, (reason_for_change?reason_for_change:"N/A")); - - player->sound_focus.cb_pending = TRUE; - player->sound_focus.by_asm_cb = TRUE; -// player->sound_focus.event_src = event_src; - -#if 0 - /* first, check event source */ - if(event_src == ASM_EVENT_SOURCE_EARJACK_UNPLUG) - { - int stop_by_asm = 0; - mm_attrs_get_int_by_name(player->attrs, "sound_stop_when_unplugged", &stop_by_asm); - if (!stop_by_asm) - goto DONE; - } - else if (event_src == ASM_EVENT_SOURCE_RESOURCE_CONFLICT) - { - /* can use video overlay simultaneously */ - /* video resource conflict */ - if(player->pipeline->videobin) - { - debug_log("video conflict but, can support multiple video"); - result = _mmplayer_pause((MMHandleType)player); - cb_res = ASM_CB_RES_PAUSE; - } - else if (player->pipeline->audiobin) - { - debug_log("audio resource conflict"); - result = _mmplayer_pause((MMHandleType)player); - if (result != MM_ERROR_NONE) - { - debug_warning("fail to set pause by asm"); - } - cb_res = ASM_CB_RES_PAUSE; - } - goto DONE; - } -#if 0 // should remove - else if (event_src == ASM_EVENT_SOURCE_RESUMABLE_CANCELED) - { - debug_warning("Got msg from asm for resumable canceled.\n"); - player->sound_focus.antishock = TRUE; - player->sound_focus.by_asm_cb = FALSE; - - player->resumable_cancel_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player); - cb_res = ASM_CB_RES_IGNORE; - goto DONE; - } -#endif -#endif - - if (focus_state == FOCUS_IS_RELEASED) - { - debug_warning("FOCUS_IS_RELEASED"); - - if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg)) - { - player->sound_focus.focus_changed_msg = (int)msg; - } - - if (strstr(reason_for_change, "call") || - strstr(reason_for_change, "voip") || /* FIXME: to check */ - strstr(reason_for_change, "alarm") || - strstr(reason_for_change, "media")) - { - if (!MMPLAYER_IS_RTSP_STREAMING(player)) - { - //hold 0.7 second to excute "fadedown mute" effect - debug_warning ("do fade down->pause->undo fade down"); - - __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT); - - result = _mmplayer_pause((MMHandleType)player); - if (result != MM_ERROR_NONE) - { - debug_warning("fail to set Pause state by asm"); - goto EXIT; - } - __mmplayer_undo_sound_fadedown(player); - } - else - { - /* rtsp should connect again in specific network becasue tcp session can't be kept any more */ - _mmplayer_unrealize((MMHandleType)player); - } - } -#if 0 -#ifdef USE_LAZY_PAUSE // if enabled, should consider event id and context when removed - else if(event_src == ASM_EVENT_SOURCE_OTHER_PLAYER_APP) - { - lazy_pause = TRUE; // return as soon as possible, for fast start of other app - - if ( player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_SINK].gst ) - g_object_set( player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "mute", 2, NULL); - - player->lazy_pause_event_id = g_timeout_add(LAZY_PAUSE_TIMEOUT_MSEC, (GSourceFunc)_asm_lazy_pause, (gpointer)player); - debug_warning ("set lazy pause timer (id=[%d], timeout=[%d ms])", player->lazy_pause_event_id, LAZY_PAUSE_TIMEOUT_MSEC); - } -#endif -#endif - else - { - debug_warning ("pause immediately"); - result = _mmplayer_pause((MMHandleType)player); - if (result != MM_ERROR_NONE) - { - debug_warning("fail to set Pause state by asm"); - goto EXIT; - } - } - } - else if (focus_state == FOCUS_IS_ACQUIRED) - { - debug_warning("FOCUS_IS_ACQUIRED: Got msg from asm to resume"); - player->sound_focus.antishock = TRUE; - player->sound_focus.by_asm_cb = FALSE; - - if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg)) - { - player->sound_focus.focus_changed_msg = (int)msg; - } - - //ASM server is single thread daemon. So use g_idle_add() to post resume msg - player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player); - goto DONE; - } - else - { - debug_warning("unknown focus state %d", focus_state); - } - -DONE: - if ( !lazy_pause ) - { - player->sound_focus.by_asm_cb = FALSE; - } - player->sound_focus.cb_pending = FALSE; - MMPLAYER_CMD_UNLOCK( player ); - -EXIT: - debug_warning("dispatched"); - return; -} - - -int -_mmplayer_create_player(MMHandleType handle) // @ -{ - mm_player_t* player = MM_PLAYER_CAST(handle); - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - /* initialize player state */ - MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE; - MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE; - MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE; - MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE; - - /* check current state */ - MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_CREATE ); - - /* construct attributes */ - player->attrs = _mmplayer_construct_attribute(handle); - - if ( !player->attrs ) - { - debug_error("Failed to construct attributes\n"); - goto ERROR; - } - - /* initialize gstreamer with configured parameter */ - if ( ! __mmplayer_init_gstreamer(player) ) - { - debug_error("Initializing gstreamer failed\n"); - goto ERROR; - } - - /* initialize factories if not using decodebin */ - if( player->factories == NULL ) - __mmplayer_init_factories(player); - - /* create lock. note that g_tread_init() has already called in gst_init() */ - g_mutex_init(&player->fsink_lock); - - /* create repeat mutex */ - g_mutex_init(&player->repeat_thread_mutex); - - /* create repeat cond */ - g_cond_init(&player->repeat_thread_cond); - - /* create repeat thread */ - player->repeat_thread = - g_thread_try_new ("repeat_thread", __mmplayer_repeat_thread, (gpointer)player, NULL); - - - /* create next play mutex */ - g_mutex_init(&player->next_play_thread_mutex); - - /* create next play cond */ - g_cond_init(&player->next_play_thread_cond); - - /* create next play thread */ - player->next_play_thread = - g_thread_try_new ("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL); - if ( ! player->next_play_thread ) - { - debug_error("failed to create next play thread"); - goto ERROR; - } - - if ( MM_ERROR_NONE != _mmplayer_initialize_video_capture(player)) - { - debug_error("failed to initialize video capture\n"); - goto ERROR; - } - - /* register to asm */ - if ( MM_ERROR_NONE != _mmplayer_sound_register(&player->sound_focus, - (mm_sound_focus_changed_cb)__mmplayer_sound_focus_callback, - (mm_sound_focus_changed_watch_cb)__mmplayer_sound_focus_watch_callback, - (void*)player) ) - - { - /* NOTE : we are dealing it as an error since we cannot expect it's behavior */ - debug_error("failed to register asm server\n"); - return MM_ERROR_POLICY_INTERNAL; - } -#if 0 //need to change and test - /* to add active device callback */ - if ( MM_ERROR_NONE != mm_sound_add_device_information_changed_callback(MM_SOUND_DEVICE_STATE_ACTIVATED_FLAG, __mmplayer_sound_device_info_changed_cb_func, (void*)player)) - { - debug_error("failed mm_sound_add_device_information_changed_callback \n"); - } -#endif - if (MMPLAYER_IS_HTTP_PD(player)) - { - player->pd_downloader = NULL; - player->pd_file_save_path = NULL; - } - - player->streaming_type = STREAMING_SERVICE_NONE; - - /* give default value of audio effect setting */ - player->sound.volume = MM_VOLUME_FACTOR_DEFAULT; - player->playback_rate = DEFAULT_PLAYBACK_RATE; - - player->play_subtitle = FALSE; - player->use_textoverlay = FALSE; - player->play_count = 0; - player->use_decodebin = TRUE; - player->ignore_asyncdone = FALSE; - player->use_deinterleave = FALSE; - player->max_audio_channels = 0; - player->video_share_api_delta = 0; - player->video_share_clock_delta = 0; - player->has_closed_caption = FALSE; - - __mmplayer_post_proc_reset(player); - - if (player->ini.dump_element_keyword[0][0] == '\0') - { - player->ini.set_dump_element_flag= FALSE; - } - else - { - player->ini.set_dump_element_flag = TRUE; - } - - /* set player state to null */ - MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout; - MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_NULL ); - - return MM_ERROR_NONE; - -ERROR: - /* free lock */ - g_mutex_clear(&player->fsink_lock ); - - /* free thread */ - if ( player->repeat_thread ) - { - player->repeat_thread_exit = TRUE; - g_cond_signal( &player->repeat_thread_cond ); - - g_thread_join( player->repeat_thread ); - player->repeat_thread = NULL; - - g_mutex_clear(&player->repeat_thread_mutex ); - - g_cond_clear (&player->repeat_thread_cond ); - } - /* clear repeat thread mutex/cond if still alive - * this can happen if only thread creating has failed - */ - g_mutex_clear(&player->repeat_thread_mutex ); - g_cond_clear ( &player->repeat_thread_cond ); - - /* free next play thread */ - if ( player->next_play_thread ) - { - player->next_play_thread_exit = TRUE; - g_cond_signal( &player->next_play_thread_cond ); - - g_thread_join( player->next_play_thread ); - player->next_play_thread = NULL; - - g_mutex_clear(&player->next_play_thread_mutex ); - - g_cond_clear ( &player->next_play_thread_cond ); - } - /* clear next play thread mutex/cond if still alive - * this can happen if only thread creating has failed - */ - g_mutex_clear(&player->next_play_thread_mutex ); - - g_cond_clear ( &player->next_play_thread_cond ); - - /* release attributes */ - _mmplayer_deconstruct_attribute(handle); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_PLAYER_INTERNAL; -} - -static gboolean -__mmplayer_init_gstreamer(mm_player_t* player) // @ -{ - static gboolean initialized = FALSE; - static const int max_argc = 50; - gint* argc = NULL; - gchar** argv = NULL; - gchar** argv2 = NULL; - GError *err = NULL; - int i = 0; - int arg_count = 0; - - if ( initialized ) - { - debug_log("gstreamer already initialized.\n"); - return TRUE; - } - - /* alloc */ - argc = malloc( sizeof(int) ); - argv = malloc( sizeof(gchar*) * max_argc ); - argv2 = malloc( sizeof(gchar*) * max_argc ); - - if ( !argc || !argv ) - goto ERROR; - - memset( argv, 0, sizeof(gchar*) * max_argc ); - memset( argv2, 0, sizeof(gchar*) * max_argc ); - - /* add initial */ - *argc = 1; - argv[0] = g_strdup( "mmplayer" ); - - /* add gst_param */ - for ( i = 0; i < 5; i++ ) /* FIXIT : num of param is now fixed to 5. make it dynamic */ - { - if ( strlen( player->ini.gst_param[i] ) > 0 ) - { - argv[*argc] = g_strdup( player->ini.gst_param[i] ); - (*argc)++; - } - } - - /* we would not do fork for scanning plugins */ - argv[*argc] = g_strdup("--gst-disable-registry-fork"); - (*argc)++; - - /* check disable registry scan */ - if ( player->ini.skip_rescan ) - { - argv[*argc] = g_strdup("--gst-disable-registry-update"); - (*argc)++; - } - - /* check disable segtrap */ - if ( player->ini.disable_segtrap ) - { - argv[*argc] = g_strdup("--gst-disable-segtrap"); - (*argc)++; - } - - debug_log("initializing gstreamer with following parameter\n"); - debug_log("argc : %d\n", *argc); - arg_count = *argc; - - for ( i = 0; i < arg_count; i++ ) - { - argv2[i] = argv[i]; - debug_log("argv[%d] : %s\n", i, argv2[i]); - } - - - /* initializing gstreamer */ - if ( ! gst_init_check (argc, &argv, &err)) - { - debug_error("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred"); - if (err) - { - g_error_free (err); - } - - goto ERROR; - } - /* release */ - for ( i = 0; i < arg_count; i++ ) - { - //debug_log("release - argv[%d] : %s\n", i, argv2[i]); - MMPLAYER_FREEIF( argv2[i] ); - } - - MMPLAYER_FREEIF( argv ); - MMPLAYER_FREEIF( argv2 ); - MMPLAYER_FREEIF( argc ); - - /* done */ - initialized = TRUE; - - return TRUE; - -ERROR: - - /* release */ - for ( i = 0; i < arg_count; i++ ) - { - debug_log("free[%d] : %s\n", i, argv2[i]); - MMPLAYER_FREEIF( argv2[i] ); - } - - MMPLAYER_FREEIF( argv ); - MMPLAYER_FREEIF( argv2 ); - MMPLAYER_FREEIF( argc ); - - return FALSE; -} - -int -__mmplayer_destroy_streaming_ext(mm_player_t* player) -{ - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - if (player->pd_downloader) - { - _mmplayer_unrealize_pd_downloader((MMHandleType)player); - MMPLAYER_FREEIF(player->pd_downloader); - } - - if (MMPLAYER_IS_HTTP_PD(player)) - { - _mmplayer_destroy_pd_downloader((MMHandleType)player); - MMPLAYER_FREEIF(player->pd_file_save_path); - } - - return MM_ERROR_NONE; -} - -int -_mmplayer_destroy(MMHandleType handle) // @ -{ - mm_player_t* player = MM_PLAYER_CAST(handle); - - MMPLAYER_FENTER(); - - /* check player handle */ - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - /* destroy can called at anytime */ - MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_DESTROY ); - - __mmplayer_destroy_streaming_ext(player); - - /* release repeat thread */ - if ( player->repeat_thread ) - { - player->repeat_thread_exit = TRUE; - g_cond_signal( &player->repeat_thread_cond ); - - debug_log("waitting for repeat thread exit\n"); - g_thread_join ( player->repeat_thread ); - g_mutex_clear(&player->repeat_thread_mutex ); - g_cond_clear (&player->repeat_thread_cond ); - debug_log("repeat thread released\n"); - } - - /* release next play thread */ - if ( player->next_play_thread ) - { - player->next_play_thread_exit = TRUE; - g_cond_signal( &player->next_play_thread_cond ); - - debug_log("waitting for next play thread exit\n"); - g_thread_join ( player->next_play_thread ); - g_mutex_clear(&player->next_play_thread_mutex ); - g_cond_clear(&player->next_play_thread_cond ); - debug_log("next play thread released\n"); - } - - _mmplayer_release_video_capture(player); - - /* flush any pending asm_cb */ - if (player->sound_focus.cb_pending) - { - /* set a flag for make sure asm_cb to be returned immediately */ - debug_warning("asm cb has pending state"); - player->sound_focus.exit_cb = TRUE; - - /* make sure to release any pending asm_cb which locked by cmd_lock */ - MMPLAYER_CMD_UNLOCK(player); - sched_yield(); - MMPLAYER_CMD_LOCK(player); - } - - /* withdraw asm */ - if ( MM_ERROR_NONE != _mmplayer_sound_unregister(&player->sound_focus) ) - { - debug_error("failed to deregister asm server\n"); - } - -#ifdef USE_LAZY_PAUSE - if (player->lazy_pause_event_id) - { - __mmplayer_remove_g_source_from_context(player->context.global_default, player->lazy_pause_event_id); - player->lazy_pause_event_id = 0; - } -#endif - - if (player->resume_event_id) - { - g_source_remove (player->resume_event_id); - player->resume_event_id = 0; - } - - if (player->resumable_cancel_id) - { - g_source_remove (player->resumable_cancel_id); - player->resumable_cancel_id = 0; - } - - /* release pipeline */ - if ( MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline( player ) ) - { - debug_error("failed to destory pipeline\n"); - return MM_ERROR_PLAYER_INTERNAL; - } - - if (player->is_external_subtitle_present && player->subtitle_language_list) - { - g_list_free (player->subtitle_language_list); - player->subtitle_language_list = NULL; - } - - __mmplayer_release_dump_list (player->dump_list); - - /* release miscellaneous information. - these info needs to be released after pipeline is destroyed. */ - __mmplayer_release_misc_post( player ); - - /* release attributes */ - _mmplayer_deconstruct_attribute( handle ); - - /* release factories */ - __mmplayer_release_factories( player ); - - /* release lock */ - g_mutex_clear(&player->fsink_lock ); - - g_mutex_clear(&player->msg_cb_lock ); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -int -__mmplayer_realize_streaming_ext(mm_player_t* player) -{ - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - if (MMPLAYER_IS_HTTP_PD(player)) - { - gboolean bret = FALSE; - - player->pd_downloader = _mmplayer_create_pd_downloader(); - if ( !player->pd_downloader ) - { - debug_error ("Unable to create PD Downloader..."); - ret = MM_ERROR_PLAYER_NO_FREE_SPACE; - } - - bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst); - - if (FALSE == bret) - { - debug_error ("Unable to create PD Downloader..."); - ret = MM_ERROR_PLAYER_NOT_INITIALIZED; - } - } - - MMPLAYER_FLEAVE(); - return ret; -} - -int -_mmplayer_realize(MMHandleType hplayer) // @ -{ - mm_player_t* player = (mm_player_t*)hplayer; - char *uri =NULL; - void *param = NULL; - int application_pid = -1; - gboolean update_registry = FALSE; - MMHandleType attrs = 0; - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - /* check player handle */ - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ) - - /* check current state */ - MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_REALIZE ); - - attrs = MMPLAYER_GET_ATTRS(player); - if ( !attrs ) - { - debug_error("fail to get attributes.\n"); - return MM_ERROR_PLAYER_INTERNAL; - } - - mm_attrs_get_int_by_name(attrs, "sound_application_pid", &application_pid ); - player->sound_focus.pid = application_pid; - - mm_attrs_get_string_by_name(attrs, "profile_uri", &uri); - mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m); - - ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile); - - if (ret != MM_ERROR_NONE) - { - debug_error("failed to parse profile\n"); - return ret; - } - - /* FIXIT : we can use thouse in player->profile directly */ - if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) - { - player->mem_buf.buf = (char *)player->profile.mem; - player->mem_buf.len = player->profile.mem_size; - player->mem_buf.offset = 0; - } - - if (player->profile.uri_type == MM_PLAYER_URI_TYPE_ES_BUFF) - { - if (strstr(uri, "es_buff://push_mode")) - { - player->es_player_push_mode = TRUE; - } - else - { - player->es_player_push_mode = FALSE; - } - } - - if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) - { - debug_warning("mms protocol is not supported format.\n"); - return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT; - } - - if (MMPLAYER_IS_STREAMING(player)) - MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout; - else - MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout; - - player->smooth_streaming = FALSE; - player->videodec_linked = 0; - player->videosink_linked = 0; - player->audiodec_linked = 0; - player->audiosink_linked = 0; - player->textsink_linked = 0; - player->is_external_subtitle_present = FALSE; - /* set the subtitle ON default */ - player->is_subtitle_off = FALSE; - - /* registry should be updated for downloadable codec */ - mm_attrs_get_int_by_name(attrs, "profile_update_registry", &update_registry); - - if ( update_registry ) - { - debug_log("updating registry...\n"); - gst_update_registry(); - - /* then we have to rebuild factories */ - __mmplayer_release_factories( player ); - __mmplayer_init_factories(player); - } - - /* realize pipeline */ - ret = __gst_realize( player ); - if ( ret != MM_ERROR_NONE ) - { - debug_error("fail to realize the player.\n"); - } - else - { - ret = __mmplayer_realize_streaming_ext(player); - } - - MMPLAYER_FLEAVE(); - - return ret; -} - -int -__mmplayer_unrealize_streaming_ext(mm_player_t *player) -{ - MMPLAYER_FENTER(); - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - /* destroy can called at anytime */ - if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player)) - { - _mmplayer_unrealize_pd_downloader ((MMHandleType)player); - MMPLAYER_FREEIF(player->pd_downloader); - } - - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; -} - -int -_mmplayer_unrealize(MMHandleType hplayer) -{ - mm_player_t* player = (mm_player_t*)hplayer; - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ) - - /* check current state */ - MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_UNREALIZE ); - - __mmplayer_unrealize_streaming_ext(player); - - /* unrealize pipeline */ - ret = __gst_unrealize( player ); - - /* set asm stop if success */ - if (MM_ERROR_NONE == ret) - { - ret = _mmplayer_sound_release_focus(&player->sound_focus); - if ( ret != MM_ERROR_NONE ) - { - debug_error("failed to release sound focus\n"); - return ret; - } - } - else - { - debug_error("failed and don't change asm state to stop"); - } - - MMPLAYER_FLEAVE(); - - return ret; -} - -int -_mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param) // @ -{ - mm_player_t* player = (mm_player_t*)hplayer; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - return __gst_set_message_callback(player, callback, user_param); -} - -int -_mmplayer_get_state(MMHandleType hplayer, int* state) // @ -{ - mm_player_t *player = (mm_player_t*)hplayer; - - return_val_if_fail(state, MM_ERROR_INVALID_ARGUMENT); - - *state = MMPLAYER_CURRENT_STATE(player); - - return MM_ERROR_NONE; -} - - -int -_mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume) // @ -{ - mm_player_t* player = (mm_player_t*) hplayer; - GstElement* vol_element = NULL; - int i = 0; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - debug_log("volume [L]=%f:[R]=%f\n", - volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]); - - /* invalid factor range or not */ - for ( i = 0; i < MM_VOLUME_CHANNEL_NUM; i++ ) - { - if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) { - debug_error("Invalid factor! (valid factor:0~1.0)\n"); - return MM_ERROR_INVALID_ARGUMENT; - } - } - - /* not support to set other value into each channel */ - if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT])) - return MM_ERROR_INVALID_ARGUMENT; - - /* Save volume to handle. Currently the first array element will be saved. */ - player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT]; - - /* check pipeline handle */ - if ( ! player->pipeline || ! player->pipeline->audiobin ) - { - debug_log("audiobin is not created yet\n"); - debug_log("but, current stored volume will be set when it's created.\n"); - - /* NOTE : stored volume will be used in create_audiobin - * returning MM_ERROR_NONE here makes application to able to - * set volume at anytime. - */ - return MM_ERROR_NONE; - } - - /* setting volume to volume element */ - vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst; - - if ( vol_element ) - { - debug_log("volume is set [%f]\n", player->sound.volume); - g_object_set(vol_element, "volume", player->sound.volume, NULL); - } - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - - -int -_mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume) -{ - mm_player_t* player = (mm_player_t*) hplayer; - int i = 0; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - return_val_if_fail( volume, MM_ERROR_INVALID_ARGUMENT ); - - /* returning stored volume */ - for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) - volume->level[i] = player->sound.volume; - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - - - -int -_mmplayer_set_mute(MMHandleType hplayer, int mute) // @ -{ - mm_player_t* player = (mm_player_t*) hplayer; - GstElement* vol_element = NULL; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - /* mute value shoud 0 or 1 */ - if ( mute != 0 && mute != 1 ) - { - debug_error("bad mute value\n"); - - /* FIXIT : definitly, we need _BAD_PARAM error code */ - return MM_ERROR_INVALID_ARGUMENT; - } - - player->sound.mute = mute; - - /* just hold mute value if pipeline is not ready */ - if ( !player->pipeline || !player->pipeline->audiobin ) - { - debug_log("pipeline is not ready. holding mute value\n"); - return MM_ERROR_NONE; - } - - vol_element = player->pipeline->audiobin[MMPLAYER_A_SINK].gst; - - /* NOTE : volume will only created when the bt is enabled */ - if ( vol_element ) - { - debug_log("mute : %d\n", mute); - g_object_set(vol_element, "mute", mute, NULL); - } - else - { - debug_log("volume elemnet is not created. using volume in audiosink\n"); - } - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -int -_mmplayer_get_mute(MMHandleType hplayer, int* pmute) // @ -{ - mm_player_t* player = (mm_player_t*) hplayer; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - return_val_if_fail ( pmute, MM_ERROR_INVALID_ARGUMENT ); - - /* just hold mute value if pipeline is not ready */ - if ( !player->pipeline || !player->pipeline->audiobin ) - { - debug_log("pipeline is not ready. returning stored value\n"); - *pmute = player->sound.mute; - return MM_ERROR_NONE; - } - - *pmute = player->sound.mute; - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -int -_mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param) -{ - mm_player_t* player = (mm_player_t*) hplayer; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - player->video_stream_changed_cb = callback; - player->video_stream_changed_cb_user_param = user_param; - debug_log("Handle value is %p : %p\n", player, player->video_stream_changed_cb); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -int -_mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param) -{ - mm_player_t* player = (mm_player_t*) hplayer; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - player->audio_stream_changed_cb = callback; - player->audio_stream_changed_cb_user_param = user_param; - debug_log("Handle value is %p : %p\n", player, player->audio_stream_changed_cb); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -int -_mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param) // @ -{ - mm_player_t* player = (mm_player_t*) hplayer; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - player->audio_stream_render_cb_ex = callback; - player->audio_stream_cb_user_param = user_param; - player->audio_stream_sink_sync = sync; - debug_log("Audio Stream cb Handle value is %p : %p audio_stream_sink_sync : %d\n", player, player->audio_stream_render_cb_ex, player->audio_stream_sink_sync); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -int -_mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param) // @ -{ - mm_player_t* player = (mm_player_t*) hplayer; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - player->video_stream_cb = callback; - player->video_stream_cb_user_param = user_param; - player->use_video_stream = TRUE; - debug_log("Stream cb Handle value is %p : %p\n", player, player->video_stream_cb); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -int -_mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @ -{ - mm_player_t* player = (mm_player_t*) hplayer; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - player->audio_stream_cb = callback; - player->audio_stream_cb_user_param = user_param; - debug_log("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -// set prepare size -int -_mmplayer_set_prepare_buffering_time(MMHandleType hplayer, int second) -{ - mm_player_t* player = (mm_player_t*) hplayer; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) - return MM_ERROR_PLAYER_INVALID_STATE; - - debug_log("pre buffer size : %d sec\n", second); - - if ( second <= 0 ) - { - debug_error("bad size value\n"); - return MM_ERROR_INVALID_ARGUMENT; - } - - if (player->streamer == NULL) - { - player->streamer = __mm_player_streaming_create(); - __mm_player_streaming_initialize(player->streamer); - } - - player->streamer->buffering_req.initial_second = second; - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -// set runtime mode -int -_mmplayer_set_runtime_buffering_mode(MMHandleType hplayer, MMPlayerBufferingMode mode, int second) -{ - mm_player_t* player = (mm_player_t*) hplayer; - - MMPLAYER_FENTER(); - - return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - debug_log("mode %d\n", mode); - - if ((mode < 0) || (mode > MM_PLAYER_BUFFERING_MODE_MAX) || - ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) && (second <= 0))) - return MM_ERROR_INVALID_ARGUMENT; - - if (player->streamer == NULL) - { - player->streamer = __mm_player_streaming_create(); - __mm_player_streaming_initialize(player->streamer); - } - - player->streamer->buffering_req.mode = mode; - - if ((second > 0) && - ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) || - (mode == MM_PLAYER_BUFFERING_MODE_ADAPTIVE))) - player->streamer->buffering_req.runtime_second = second; - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -int -_mmplayer_set_videoframe_render_error_cb(MMHandleType hplayer, mm_player_video_frame_render_error_callback callback, void *user_param) // @ -{ - mm_player_t* player = (mm_player_t*) hplayer; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - return_val_if_fail ( callback, MM_ERROR_INVALID_ARGUMENT ); - - player->video_frame_render_error_cb = callback; - player->video_frame_render_error_cb_user_param = user_param; - - debug_log("Video frame render error cb Handle value is %p : %p\n", player, player->video_frame_render_error_cb); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -int -__mmplayer_start_streaming_ext(mm_player_t *player) -{ - gint ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - if (MMPLAYER_IS_HTTP_PD(player)) - { - if ( !player->pd_downloader ) - { - ret = __mmplayer_realize_streaming_ext(player); - - if ( ret != MM_ERROR_NONE) - { - debug_error ("failed to realize streaming ext\n"); - return ret; - } - } - - if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) - { - ret = _mmplayer_start_pd_downloader ((MMHandleType)player); - if ( !ret ) - { - debug_error ("ERROR while starting PD...\n"); - return MM_ERROR_PLAYER_NOT_INITIALIZED; - } - ret = MM_ERROR_NONE; - } - } - - MMPLAYER_FLEAVE(); - return ret; -} - -int -_mmplayer_start(MMHandleType hplayer) // @ -{ - mm_player_t* player = (mm_player_t*) hplayer; - gint ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - /* check current state */ - MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_START ); - - ret = _mmplayer_sound_acquire_focus(&player->sound_focus); - if ( ret != MM_ERROR_NONE ) - { - debug_error("failed to acquire sound focus.\n"); - return ret; - } - - /* NOTE : we should check and create pipeline again if not created as we destroy - * whole pipeline when stopping in streamming playback - */ - if ( ! player->pipeline ) - { - ret = __gst_realize( player ); - if ( MM_ERROR_NONE != ret ) - { - debug_error("failed to realize before starting. only in streamming\n"); - /* unlock */ - return ret; - } - } - - ret = __mmplayer_start_streaming_ext(player); - if ( ret != MM_ERROR_NONE ) - { - debug_error("failed to start streaming ext \n"); - } - - /* start pipeline */ - ret = __gst_start( player ); - if ( ret != MM_ERROR_NONE ) - { - debug_error("failed to start player.\n"); - } - - MMPLAYER_FLEAVE(); - - return ret; -} - -/* NOTE: post "not supported codec message" to application - * when one codec is not found during AUTOPLUGGING in MSL. - * So, it's separated with error of __mmplayer_gst_callback(). - * And, if any codec is not found, don't send message here. - * Because GST_ERROR_MESSAGE is posted by other plugin internally. - */ -int -__mmplayer_handle_missed_plugin(mm_player_t* player) -{ - MMMessageParamType msg_param; - memset (&msg_param, 0, sizeof(MMMessageParamType)); - gboolean post_msg_direct = FALSE; - - MMPLAYER_FENTER(); - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - debug_log("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n", - player->not_supported_codec, player->can_support_codec); - - if( player->not_found_demuxer ) - { - msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND; - msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime); - - MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param ); - MMPLAYER_FREEIF(msg_param.data); - - return MM_ERROR_NONE; - } - - if (player->not_supported_codec) - { - if ( player->can_support_codec ) // There is one codec to play - { - post_msg_direct = TRUE; - } - else - { - if ( player->pipeline->audiobin ) // Some content has only PCM data in container. - post_msg_direct = TRUE; - } - - if ( post_msg_direct ) - { - MMMessageParamType msg_param; - memset (&msg_param, 0, sizeof(MMMessageParamType)); - - if ( player->not_supported_codec == MISSING_PLUGIN_AUDIO ) - { - debug_warning("not found AUDIO codec, posting error code to application.\n"); - - msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND; - msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime); - } - else if ( player->not_supported_codec == MISSING_PLUGIN_VIDEO ) - { - debug_warning("not found VIDEO codec, posting error code to application.\n"); - - msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND; - msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime); - } - - MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param ); - - MMPLAYER_FREEIF(msg_param.data); - - return MM_ERROR_NONE; - } - else // no any supported codec case - { - debug_warning("not found any codec, posting error code to application.\n"); - - if ( player->not_supported_codec == MISSING_PLUGIN_AUDIO ) - { - msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND; - msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime); - } - else - { - msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND; - msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime); - } - - MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param ); - - MMPLAYER_FREEIF(msg_param.data); - } - } - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -static void __mmplayer_check_pipeline(mm_player_t* player) -{ - GstState element_state = GST_STATE_VOID_PENDING; - GstState element_pending_state = GST_STATE_VOID_PENDING; - gint timeout = 0; - int ret = MM_ERROR_NONE; - - if (player->gapless.reconfigure) - { - debug_warning("pipeline is under construction.\n"); - - MMPLAYER_PLAYBACK_LOCK(player); - MMPLAYER_PLAYBACK_UNLOCK(player); - - timeout = MMPLAYER_STATE_CHANGE_TIMEOUT ( player ); - - /* wait for state transition */ - ret = gst_element_get_state( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND ); - - if ( ret == GST_STATE_CHANGE_FAILURE ) - { - debug_error("failed to change pipeline state within %d sec\n", timeout ); - } - } -} - -/* NOTE : it should be able to call 'stop' anytime*/ -int -_mmplayer_stop(MMHandleType hplayer) // @ -{ - mm_player_t* player = (mm_player_t*)hplayer; - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - /* check current state */ - MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_STOP ); - - /* check pipline building state */ - __mmplayer_check_pipeline(player); - player->gapless.start_time = 0; - - /* NOTE : application should not wait for EOS after calling STOP */ - __mmplayer_cancel_eos_timer( player ); - - __mmplayer_unrealize_streaming_ext(player); - - /* reset */ - player->doing_seek = FALSE; - - /* stop pipeline */ - ret = __gst_stop( player ); - - if ( ret != MM_ERROR_NONE ) - { - debug_error("failed to stop player.\n"); - } - - MMPLAYER_FLEAVE(); - - return ret; -} - -int -_mmplayer_pause(MMHandleType hplayer) // @ -{ - mm_player_t* player = (mm_player_t*)hplayer; - gint64 pos_msec = 0; - gboolean async = FALSE; - gint ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - /* check current state */ - MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_PAUSE ); - - /* check pipline building state */ - __mmplayer_check_pipeline(player); - - switch (MMPLAYER_CURRENT_STATE(player)) - { - case MM_PLAYER_STATE_READY: - { - /* check prepare async or not. - * In the case of streaming playback, it's recommned to avoid blocking wait. - */ - mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async); - debug_log("prepare working mode : %s", (async ? "async" : "sync")); - } - break; - - case MM_PLAYER_STATE_PLAYING: - { - /* NOTE : store current point to overcome some bad operation - * ( returning zero when getting current position in paused state) of some - * elements - */ - if ( !gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec)) - debug_warning("getting current position failed in paused\n"); - - player->last_position = pos_msec; - } - break; - } - - /* pause pipeline */ - ret = __gst_pause( player, async ); - - if ( ret != MM_ERROR_NONE ) - { - debug_error("failed to pause player. ret : 0x%x\n", ret); - } - - MMPLAYER_FLEAVE(); - - return ret; -} - -int -_mmplayer_resume(MMHandleType hplayer) -{ - mm_player_t* player = (mm_player_t*)hplayer; - int ret = MM_ERROR_NONE; - gboolean async = FALSE; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - ret = _mmplayer_sound_acquire_focus(&player->sound_focus); - if ( ret != MM_ERROR_NONE ) - { - debug_error("failed to acquire sound focus.\n"); - return ret; - } - - /* check current state */ - MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_RESUME ); - - ret = __gst_resume( player, async ); - - if ( ret != MM_ERROR_NONE ) - { - debug_error("failed to resume player.\n"); - } - - MMPLAYER_FLEAVE(); - - return ret; -} - -int -__mmplayer_set_play_count(mm_player_t* player, gint count) -{ - MMHandleType attrs = 0; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - attrs = MMPLAYER_GET_ATTRS(player); - if ( !attrs ) - { - debug_error("fail to get attributes.\n"); - return MM_ERROR_PLAYER_INTERNAL; - } - - mm_attrs_set_int_by_name(attrs, "profile_play_count", count); - if ( mmf_attrs_commit ( attrs ) ) /* return -1 if error */ - debug_error("failed to commit\n"); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -int -_mmplayer_activate_section_repeat(MMHandleType hplayer, unsigned long start, unsigned long end) -{ - mm_player_t* player = (mm_player_t*)hplayer; - gint64 start_pos = 0; - gint64 end_pos = 0; - gint infinity = -1; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - return_val_if_fail ( end <= GST_TIME_AS_MSECONDS(player->duration), MM_ERROR_INVALID_ARGUMENT ); - - player->section_repeat = TRUE; - player->section_repeat_start = start; - player->section_repeat_end = end; - - start_pos = player->section_repeat_start * G_GINT64_CONSTANT(1000000); - end_pos = player->section_repeat_end * G_GINT64_CONSTANT(1000000); - - __mmplayer_set_play_count( player, infinity ); - - if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, - player->playback_rate, - GST_FORMAT_TIME, - ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ), - GST_SEEK_TYPE_SET, start_pos, - GST_SEEK_TYPE_SET, end_pos))) - { - debug_error("failed to activate section repeat\n"); - - return MM_ERROR_PLAYER_SEEK; - } - - debug_log("succeeded to set section repeat from %d to %d\n", - player->section_repeat_start, player->section_repeat_end); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -static int -__mmplayer_set_pcm_extraction(mm_player_t* player) -{ - gint64 start_nsec = 0; - gint64 end_nsec = 0; - gint64 dur_nsec = 0; - gint64 dur_msec = 0; - int required_start = 0; - int required_end = 0; - int ret = 0; - - MMPLAYER_FENTER(); - - return_val_if_fail( player, FALSE ); - - mm_attrs_multiple_get(player->attrs, - NULL, - "pcm_extraction_start_msec", &required_start, - "pcm_extraction_end_msec", &required_end, - NULL); - - debug_log("pcm extraction required position is from [%d] to [%d] (msec)\n", required_start, required_end); - - if (required_start == 0 && required_end == 0) - { - debug_log("extracting entire stream"); - return MM_ERROR_NONE; - } - else if (required_start < 0 || required_start > required_end || required_end < 0 ) - { - debug_log("invalid range for pcm extraction"); - return MM_ERROR_INVALID_ARGUMENT; - } - - /* get duration */ - ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec); - if ( !ret ) - { - debug_error("failed to get duration"); - return MM_ERROR_PLAYER_INTERNAL; - } - dur_msec = GST_TIME_AS_MSECONDS(dur_nsec); - - if (dur_msec < required_end) // FIXME - { - debug_log("invalid end pos for pcm extraction"); - return MM_ERROR_INVALID_ARGUMENT; - } - - start_nsec = required_start * G_GINT64_CONSTANT(1000000); - end_nsec = required_end * G_GINT64_CONSTANT(1000000); - - if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, - 1.0, - GST_FORMAT_TIME, - ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ), - GST_SEEK_TYPE_SET, start_nsec, - GST_SEEK_TYPE_SET, end_nsec))) - { - debug_error("failed to seek for pcm extraction\n"); - - return MM_ERROR_PLAYER_SEEK; - } - - debug_log("succeeded to set up segment extraction from [%llu] to [%llu] (nsec)\n", start_nsec, end_nsec); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -int -_mmplayer_deactivate_section_repeat(MMHandleType hplayer) -{ - mm_player_t* player = (mm_player_t*)hplayer; - gint64 cur_pos = 0; - gint onetime = 1; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - player->section_repeat = FALSE; - - __mmplayer_set_play_count( player, onetime ); - - gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_pos); - - if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, - 1.0, - GST_FORMAT_TIME, - ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ), - GST_SEEK_TYPE_SET, cur_pos, - GST_SEEK_TYPE_SET, player->duration ))) - { - debug_error("failed to deactivate section repeat\n"); - - return MM_ERROR_PLAYER_SEEK; - } - - MMPLAYER_FENTER(); - - return MM_ERROR_NONE; -} - -int -_mmplayer_set_playspeed(MMHandleType hplayer, float rate) -{ - mm_player_t* player = (mm_player_t*)hplayer; - gint64 pos_msec = 0; - int ret = MM_ERROR_NONE; - int mute = FALSE; - signed long long start = 0, stop = 0; - MMPlayerStateType current_state = MM_PLAYER_STATE_NONE; - MMPLAYER_FENTER(); - - return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED ); - return_val_if_fail ( !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API ); - - /* The sound of video is not supported under 0.0 and over 2.0. */ - if(rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) - { - if (player->can_support_codec & FOUND_PLUGIN_VIDEO) - mute = TRUE; - } - _mmplayer_set_mute(hplayer, mute); - - if (player->playback_rate == rate) - return MM_ERROR_NONE; - - /* If the position is reached at start potion during fast backward, EOS is posted. - * So, This EOS have to be classified with it which is posted at reaching the end of stream. - * */ - player->playback_rate = rate; - - current_state = MMPLAYER_CURRENT_STATE(player); - - if ( current_state != MM_PLAYER_STATE_PAUSED ) - ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec); - - debug_log ("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS (pos_msec), ret, current_state); - - if ( ( current_state == MM_PLAYER_STATE_PAUSED ) - || ( ! ret )) - //|| ( player->last_position != 0 && pos_msec == 0 ) ) - { - debug_warning("returning last point : %lld\n", player->last_position ); - pos_msec = player->last_position; - } - - - if(rate >= 0) - { - start = pos_msec; - stop = GST_CLOCK_TIME_NONE; - } - else - { - start = GST_CLOCK_TIME_NONE; - stop = pos_msec; - } - if ((!gst_element_seek (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, - rate, - GST_FORMAT_TIME, - ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ), - GST_SEEK_TYPE_SET, start, - GST_SEEK_TYPE_SET, stop))) - { - debug_error("failed to set speed playback\n"); - return MM_ERROR_PLAYER_SEEK; - } - - debug_log("succeeded to set speed playback as %0.1f\n", rate); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE;; -} - -int -_mmplayer_set_position(MMHandleType hplayer, int format, int position) // @ -{ - mm_player_t* player = (mm_player_t*)hplayer; - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - ret = __gst_set_position ( player, format, (unsigned long)position, FALSE ); - - MMPLAYER_FLEAVE(); - - return ret; -} - -int -_mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position) // @ -{ - mm_player_t* player = (mm_player_t*)hplayer; - int ret = MM_ERROR_NONE; - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - ret = __gst_get_position ( player, format, position ); - - return ret; -} - -int -_mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos) // @ -{ - mm_player_t* player = (mm_player_t*)hplayer; - int ret = MM_ERROR_NONE; - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - ret = __gst_get_buffer_position ( player, format, start_pos, stop_pos ); - - return ret; -} - -int -_mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position) // @ -{ - mm_player_t* player = (mm_player_t*)hplayer; - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - ret = __gst_adjust_subtitle_position(player, format, position); - - MMPLAYER_FLEAVE(); - - return ret; -} -int -_mmplayer_adjust_video_postion(MMHandleType hplayer, int offset) // @ -{ - mm_player_t* player = (mm_player_t*)hplayer; - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - ret = __gst_adjust_video_position(player, offset); - - MMPLAYER_FLEAVE(); - - return ret; -} - -static gboolean -__mmplayer_is_midi_type( gchar* str_caps) -{ - if ( ( g_strrstr(str_caps, "audio/midi") ) || - ( g_strrstr(str_caps, "application/x-gst_ff-mmf") ) || - ( g_strrstr(str_caps, "application/x-smaf") ) || - ( g_strrstr(str_caps, "audio/x-imelody") ) || - ( g_strrstr(str_caps, "audio/mobile-xmf") ) || - ( g_strrstr(str_caps, "audio/xmf") ) || - ( g_strrstr(str_caps, "audio/mxmf") ) ) - { - debug_log("midi\n"); - - return TRUE; - } - - return FALSE; -} - -static gboolean -__mmplayer_is_only_mp3_type (gchar *str_caps) -{ - if (g_strrstr(str_caps, "application/x-id3") || - (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1"))) - { - return TRUE; - } - return FALSE; -} - -static void -__mmplayer_set_audio_attrs (mm_player_t* player, GstCaps* caps) -{ - GstStructure* caps_structure = NULL; - gint samplerate = 0; - gint channels = 0; - - MMPLAYER_FENTER(); - return_if_fail (player && caps); - - caps_structure = gst_caps_get_structure(caps, 0); - - /* set stream information */ - gst_structure_get_int (caps_structure, "rate", &samplerate); - mm_attrs_set_int_by_name (player->attrs, "content_audio_samplerate", samplerate); - - gst_structure_get_int (caps_structure, "channels", &channels); - mm_attrs_set_int_by_name (player->attrs, "content_audio_channels", channels); - - debug_log ("audio samplerate : %d channels : %d\n", samplerate, channels); -} - -static void -__mmplayer_update_content_type_info(mm_player_t* player) -{ - MMPLAYER_FENTER(); - return_if_fail( player && player->type); - - if (__mmplayer_is_midi_type(player->type)) - { - player->bypass_audio_effect = TRUE; - } - else if (g_strrstr(player->type, "application/x-hls")) - { - /* If it can't know exact type when it parses uri because of redirection case, - * it will be fixed by typefinder or when doing autoplugging. - */ - player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS; - if (player->streamer) - { - player->streamer->is_adaptive_streaming = TRUE; - player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED; - player->streamer->buffering_req.runtime_second = 5; - } - } - else if (g_strrstr(player->type, "application/dash+xml")) - { - player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH; - } - - MMPLAYER_FLEAVE(); -} - -static void -__mmplayer_typefind_have_type( GstElement *tf, guint probability, // @ -GstCaps *caps, gpointer data) -{ - mm_player_t* player = (mm_player_t*)data; - GstPad* pad = NULL; - - MMPLAYER_FENTER(); - - return_if_fail( player && tf && caps ); - - /* store type string */ - MMPLAYER_FREEIF(player->type); - player->type = gst_caps_to_string(caps); - if (player->type) - debug_log("meida type %s found, probability %d%% / %d\n", player->type, probability, gst_caps_get_size(caps)); - - if ( (!MMPLAYER_IS_WFD_STREAMING( player )) && - (!MMPLAYER_IS_RTSP_STREAMING( player )) && - (g_strrstr(player->type, "audio/x-raw-int"))) - { - debug_error("not support media format\n"); - - if (player->msg_posted == FALSE) - { - MMMessageParamType msg_param; - memset (&msg_param, 0, sizeof(MMMessageParamType)); - - msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT; - MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param ); - - /* don't post more if one was sent already */ - player->msg_posted = TRUE; - } - return; - } - - __mmplayer_update_content_type_info(player); - - pad = gst_element_get_static_pad(tf, "src"); - if ( !pad ) - { - debug_error("fail to get typefind src pad.\n"); - return; - } - - if (player->use_decodebin) - { - if(!__mmplayer_try_to_plug_decodebin( player, pad, caps )) - { - gboolean async = FALSE; - debug_error("failed to autoplug %s\n", player->type); - - mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async); - - if ( async && player->msg_posted == FALSE ) - { - __mmplayer_handle_missed_plugin( player ); - } - - goto DONE; - } - } - else - { - /* try to plug */ - if ( ! __mmplayer_try_to_plug( player, pad, caps ) ) - { - gboolean async = FALSE; - debug_error("failed to autoplug %s\n", player->type); - - mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async); - - if ( async && player->msg_posted == FALSE ) - { - __mmplayer_handle_missed_plugin( player ); - } - - goto DONE; - } - - /* finish autopluging if no dynamic pad waiting */ - if( ( ! player->have_dynamic_pad) && ( ! player->has_many_types) ) - { - if ( ! MMPLAYER_IS_RTSP_STREAMING( player ) ) - { - __mmplayer_pipeline_complete( NULL, (gpointer)player ); - } - } - } - -DONE: - gst_object_unref( GST_OBJECT(pad) ); - - MMPLAYER_FLEAVE(); - - return; -} - -#ifdef _MM_PLAYER_ALP_PARSER -void check_name (void *data, void *user_data) -{ - mm_player_t* player = user_data; - - if (g_strrstr((gchar*)data, "mpegaudioparse")) - { - debug_log("mpegaudioparse - set alp-mp3dec\n"); - g_object_set(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "alp-mp3dec", TRUE, NULL); - } -} -#endif - -static GstElement * -__mmplayer_create_decodebin (mm_player_t* player) -{ - GstElement *decodebin = NULL; - - MMPLAYER_FENTER(); - - /* create decodebin */ - decodebin = gst_element_factory_make("decodebin", NULL); - - if (!decodebin) - { - debug_error("fail to create decodebin\n"); - goto ERROR; - } - - /* raw pad handling signal */ - MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", - G_CALLBACK(__mmplayer_gst_decode_pad_added), player); - - /* no-more-pad pad handling signal */ - MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", - G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player); - - MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", - G_CALLBACK(__mmplayer_gst_decode_pad_removed), player); - - /* This signal is emitted when a pad for which there is no further possible - decoding is added to the decodebin.*/ - MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type", - G_CALLBACK(__mmplayer_gst_decode_unknown_type), player ); - - /* This signal is emitted whenever decodebin finds a new stream. It is emitted - before looking for any elements that can handle that stream.*/ - MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue", - G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player); - - /* This signal is emitted whenever decodebin finds a new stream. It is emitted - before looking for any elements that can handle that stream.*/ - MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", - G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player); - - /* This signal is emitted once decodebin has finished decoding all the data.*/ - MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained", - G_CALLBACK(__mmplayer_gst_decode_drained), player); - - /* This signal is emitted when a element is added to the bin.*/ - MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added", - G_CALLBACK(__mmplayer_gst_element_added), player); - -ERROR: - return decodebin; -} - -static gboolean -__mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps) -{ - MMPlayerGstElement* mainbin = NULL; - GstElement* decodebin = NULL; - GstElement* queue2 = NULL; - GstPad* sinkpad = NULL; - GstPad* qsrcpad= NULL; - gchar *caps_str = NULL; - gint64 dur_bytes = 0L; - gchar* file_buffering_path = NULL; - gboolean use_file_buffer = FALSE; - - guint max_buffer_size_bytes = 0; - gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second; - - MMPLAYER_FENTER(); - return_val_if_fail (player && player->pipeline && player->pipeline->mainbin, FALSE); - - mainbin = player->pipeline->mainbin; - - if ((!MMPLAYER_IS_HTTP_PD(player)) && - (MMPLAYER_IS_HTTP_STREAMING(player))) - { - debug_log ("creating http streaming buffering queue (queue2)\n"); - - if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) - { - debug_error ("MMPLAYER_M_MUXED_S_BUFFER is not null\n"); - } - else - { - queue2 = gst_element_factory_make ("queue2", "queue2"); - if (!queue2) - { - debug_error ("failed to create buffering queue element\n"); - goto ERROR; - } - - if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) - { - debug_error("failed to add buffering queue\n"); - goto ERROR; - } - - sinkpad = gst_element_get_static_pad(queue2, "sink"); - qsrcpad = gst_element_get_static_pad(queue2, "src"); - - if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) - { - debug_error("failed to link buffering queue\n"); - goto ERROR; - } - - // if ( !MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) - { - if ( !gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes)) - debug_error("fail to get duration.\n"); - - debug_log("dur_bytes = %lld\n", dur_bytes); - - if (dur_bytes > 0) - { - use_file_buffer = MMPLAYER_USE_FILE_FOR_BUFFERING(player); - file_buffering_path = g_strdup(player->ini.http_file_buffer_path); - } - else - { - dur_bytes = 0; - } - } - - /* NOTE : we cannot get any duration info from ts container in case of streaming */ - // if(!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux")) - if(!g_strrstr(player->type, "video/mpegts")) - { - max_buffer_size_bytes = (use_file_buffer)?(player->ini.http_max_size_bytes):(5*1024*1024); - debug_log("max_buffer_size_bytes = %d\n", max_buffer_size_bytes); - - __mm_player_streaming_set_queue2(player->streamer, - queue2, - FALSE, - max_buffer_size_bytes, - player->ini.http_buffering_time, - 1.0, // no meaning - player->ini.http_buffering_limit, // no meaning - use_file_buffer, - file_buffering_path, - (guint64)dur_bytes); - } - - MMPLAYER_FREEIF(file_buffering_path); - if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent (queue2)) - { - debug_error("failed to sync queue2 state with parent\n"); - goto ERROR; - } - - srcpad = qsrcpad; - - gst_object_unref(GST_OBJECT(sinkpad)); - - mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER; - mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2; - } - } - - /* create decodebin */ - decodebin = __mmplayer_create_decodebin(player); - - if (!decodebin) - { - debug_error("can not create autoplug element\n"); - goto ERROR; - } - - if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) - { - debug_error("failed to add decodebin\n"); - goto ERROR; - } - - /* to force caps on the decodebin element and avoid reparsing stuff by - * typefind. It also avoids a deadlock in the way typefind activates pads in - * the state change */ - g_object_set (decodebin, "sink-caps", caps, NULL); - - sinkpad = gst_element_get_static_pad(decodebin, "sink"); - - if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) - { - debug_error("failed to link decodebin\n"); - goto ERROR; - } - - gst_object_unref(GST_OBJECT(sinkpad)); - - mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG; - mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin; - - /* set decodebin property about buffer in streaming playback. * - * in case of hls, it does not need to have big buffer * - * because it is kind of adaptive streaming. */ - if ( ((!MMPLAYER_IS_HTTP_PD(player)) && - (MMPLAYER_IS_HTTP_STREAMING(player))) || MMPLAYER_IS_DASH_STREAMING (player)) - { - guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES; - guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME; - init_buffering_time = (init_buffering_time != 0)?(init_buffering_time):(player->ini.http_buffering_time); - - if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) { - max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES; - max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME; - } - - g_object_set (G_OBJECT(decodebin), "use-buffering", TRUE, - "high-percent", (gint)player->ini.http_buffering_limit, - "low-percent", 1, // 1% - "max-size-bytes", max_size_bytes, - "max-size-time", (guint64)(max_size_time * GST_SECOND), - "max-size-buffers", 0, NULL); // disable or automatic - } - - if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) - { - debug_error("failed to sync decodebin state with parent\n"); - goto ERROR; - } - - MMPLAYER_FLEAVE(); - - return TRUE; - -ERROR: - - MMPLAYER_FREEIF( caps_str ); - - if (sinkpad) - gst_object_unref(GST_OBJECT(sinkpad)); - - if (queue2) - { - /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state. - * You need to explicitly set elements to the NULL state before - * dropping the final reference, to allow them to clean up. - */ - gst_element_set_state(queue2, GST_STATE_NULL); - - /* And, it still has a parent "player". - * You need to let the parent manage the object instead of unreffing the object directly. - */ - gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2); - gst_object_unref (queue2); - queue2 = NULL; - } - - if (decodebin) - { - /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state. - * You need to explicitly set elements to the NULL state before - * dropping the final reference, to allow them to clean up. - */ - gst_element_set_state(decodebin, GST_STATE_NULL); - - /* And, it still has a parent "player". - * You need to let the parent manage the object instead of unreffing the object directly. - */ - - gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin); - gst_object_unref (decodebin); - decodebin = NULL; - } - - return FALSE; -} - -/* it will return first created element */ -static gboolean -__mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps) // @ -{ - MMPlayerGstElement* mainbin = NULL; - const char* mime = NULL; - const GList* item = NULL; - const gchar* klass = NULL; - GstCaps* res = NULL; - gboolean skip = FALSE; - GstPad* queue_pad = NULL; - GstElement* queue = NULL; - GstElement *element = NULL; - - MMPLAYER_FENTER(); - - return_val_if_fail( player && player->pipeline && player->pipeline->mainbin, FALSE ); - - mainbin = player->pipeline->mainbin; - - mime = gst_structure_get_name(gst_caps_get_structure(caps, 0)); - - /* return if we got raw output */ - if(g_str_has_prefix(mime, "video/x-raw") || g_str_has_prefix(mime, "audio/x-raw") - || g_str_has_prefix(mime, "text/plain") ||g_str_has_prefix(mime, "text/x-pango-markup")) - { - - element = (GstElement*)gst_pad_get_parent(pad); -/* NOTE : When no decoder has added during autoplugging. like a simple wave playback. - * No queue will be added. I think it can caused breaking sound when playing raw audio - * frames but there's no different. Decodebin also doesn't add with those wav fils. - * Anyway, currentely raw-queue seems not necessary. - */ -#if 1 - /* NOTE : check if previously linked element is demuxer/depayloader/parse means no decoder - * has linked. if so, we need to add queue for quality of output. note that - * decodebin also has same problem. - */ - klass = gst_element_factory_get_metadata (gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS); - - /* add queue if needed */ - if( (g_strrstr(klass, "Demux") || g_strrstr(klass, "Depayloader") - || g_strrstr(klass, "Parse")) && !g_str_has_prefix(mime, "text")) - { - debug_log("adding raw queue\n"); - - queue = gst_element_factory_make("queue", NULL); - if ( ! queue ) - { - debug_warning("failed to create queue\n"); - goto ERROR; - } - - /* warmup */ - if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY) ) - { - debug_warning("failed to set state READY to queue\n"); - goto ERROR; - } - - /* add to pipeline */ - if ( ! gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue) ) - { - debug_warning("failed to add queue\n"); - goto ERROR; - } - - /* link queue */ - queue_pad = gst_element_get_static_pad(queue, "sink"); - - if ( GST_PAD_LINK_OK != gst_pad_link(pad, queue_pad) ) - { - debug_warning("failed to link queue\n"); - goto ERROR; - } - gst_object_unref ( GST_OBJECT(queue_pad) ); - queue_pad = NULL; - - /* running */ - if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED) ) - { - debug_warning("failed to set state PAUSED to queue\n"); - goto ERROR; - } - - /* replace given pad to queue:src */ - pad = gst_element_get_static_pad(queue, "src"); - if ( ! pad ) - { - debug_warning("failed to get pad from queue\n"); - goto ERROR; - } - } -#endif - /* check if player can do start continually */ - MMPLAYER_CHECK_CMD_IF_EXIT(player); - - if(__mmplayer_link_sink(player,pad)) - __mmplayer_gst_decode_callback(element, pad, player); - - gst_object_unref( GST_OBJECT(element)); - element = NULL; - - return TRUE; - } - - item = player->factories; - for(; item != NULL ; item = item->next) - { - GstElementFactory *factory = GST_ELEMENT_FACTORY(item->data); - const GList *pads; - gint idx = 0; - - skip = FALSE; - - /* filtering exclude keyword */ - for ( idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++ ) - { - if ( g_strrstr(GST_OBJECT_NAME (factory), - player->ini.exclude_element_keyword[idx] ) ) - { - debug_warning("skipping [%s] by exculde keyword [%s]\n", - GST_OBJECT_NAME (factory), - player->ini.exclude_element_keyword[idx] ); - - skip = TRUE; - break; - } - } - - if ( MMPLAYER_IS_RTSP_STREAMING(player) && g_strrstr(GST_OBJECT_NAME (factory), "omx_mpeg4dec")) - { - // omx decoder can not support mpeg4video data partitioned - // rtsp streaming didn't know mpeg4video data partitioned format - // so, if rtsp playback, player will skip omx_mpeg4dec. - debug_warning("skipping [%s] when rtsp streaming \n", - GST_OBJECT_NAME (factory)); - - skip = TRUE; - } - - if ( skip ) continue; - - /* check factory class for filtering */ - klass = gst_element_factory_get_metadata (GST_ELEMENT_FACTORY(factory), GST_ELEMENT_METADATA_KLASS); - - /*parsers are not required in case of external feeder*/ - if (g_strrstr(klass, "Codec/Parser") && MMPLAYER_IS_ES_BUFF_SRC(player)) - continue; - - /* NOTE : msl don't need to use image plugins. - * So, those plugins should be skipped for error handling. - */ - if ( g_strrstr(klass, "Codec/Decoder/Image") ) - { - debug_log("skipping [%s] by not required\n", GST_OBJECT_NAME (factory)); - continue; - } - - /* check pad compatability */ - for(pads = gst_element_factory_get_static_pad_templates(factory); - pads != NULL; pads=pads->next) - { - GstStaticPadTemplate *temp1 = pads->data; - GstCaps* static_caps = NULL; - - if( temp1->direction != GST_PAD_SINK - || temp1->presence != GST_PAD_ALWAYS) - continue; - - if ( GST_IS_CAPS( &temp1->static_caps.caps) ) - { - /* using existing caps */ - static_caps = gst_caps_ref(temp1->static_caps.caps ); - } - else - { - /* create one */ - static_caps = gst_caps_from_string ( temp1->static_caps.string ); - } - - res = gst_caps_intersect((GstCaps*)caps, static_caps); - gst_caps_unref( static_caps ); - static_caps = NULL; - - if( res && !gst_caps_is_empty(res) ) - { - GstElement *new_element; - GList *elements = player->parsers; - char *name_template = g_strdup(temp1->name_template); - gchar *name_to_plug = GST_OBJECT_NAME(factory); - gst_caps_unref(res); - - /* check ALP Codec can be used or not */ - if ((g_strrstr(klass, "Codec/Decoder/Audio"))) - { - /* consider mp3 audio only */ - if ( !MMPLAYER_IS_STREAMING(player) && __mmplayer_is_only_mp3_type(player->type) ) - { - /* try to use ALP decoder first instead of selected decoder */ - GstElement *element = NULL; - GstElementFactory * element_facory; - gchar *path = NULL; - guint64 data_size = 0; - #define MIN_THRESHOLD_SIZE 320 * 1024 // 320K - struct stat sb; - - mm_attrs_get_string_by_name(player->attrs, "profile_uri", &path); - - if (stat(path, &sb) == 0) - { - data_size = (guint64)sb.st_size; - } - debug_log("file size : %u", data_size); - - if (data_size > MIN_THRESHOLD_SIZE) - { - debug_log("checking if ALP can be used or not"); - element = gst_element_factory_make("omx_mp3dec", "omx mp3 decoder"); - if ( element ) - { - /* check availability because multi-instance is not supported */ - GstStateChangeReturn ret = gst_element_set_state(element, GST_STATE_READY); - - if (ret != GST_STATE_CHANGE_SUCCESS) // use just selected decoder - { - gst_object_unref (element); - } - else if (ret == GST_STATE_CHANGE_SUCCESS) // replace facotry to use omx - { - /* clean */ - gst_element_set_state(element, GST_STATE_NULL); - gst_object_unref (element); - - element_facory = gst_element_factory_find("omx_mp3dec"); - /* replace, otherwise use selected thing instead */ - if (element_facory) - { - factory = element_facory; - name_to_plug = GST_OBJECT_NAME(factory); - } - - /* make parser alp mode */ - #ifdef _MM_PLAYER_ALP_PARSER - g_list_foreach (player->parsers, check_name, player); - #endif - } - } - } - } - } - else if ((g_strrstr(klass, "Codec/Decoder/Video"))) - { - if ( g_strrstr(GST_OBJECT_NAME(factory), "omx_") ) - { - char *env = getenv ("MM_PLAYER_HW_CODEC_DISABLE"); - if (env != NULL) - { - if (strncasecmp(env, "yes", 3) == 0) - { - debug_log("skipping [%s] by disabled\n", name_to_plug); - MMPLAYER_FREEIF(name_template); - continue; - } - } - } - } - - debug_log("found %s to plug\n", name_to_plug); - - new_element = gst_element_factory_create(GST_ELEMENT_FACTORY(factory), NULL); - if ( ! new_element ) - { - debug_error("failed to create element [%s]. continue with next.\n", - GST_OBJECT_NAME (factory)); - - MMPLAYER_FREEIF(name_template); - - continue; - } - - /* check and skip it if it was already used. Otherwise, it can be an infinite loop - * because parser can accept its own output as input. - */ - if (g_strrstr(klass, "Parser")) - { - gchar *selected = NULL; - - for ( ; elements; elements = g_list_next(elements)) - { - gchar *element_name = elements->data; - - if (g_strrstr(element_name, name_to_plug)) - { - debug_log("but, %s already linked, so skipping it\n", name_to_plug); - skip = TRUE; - } - } - - if (skip) - { - MMPLAYER_FREEIF(name_template); - continue; - } - - selected = g_strdup(name_to_plug); - player->parsers = g_list_append(player->parsers, selected); - } - - /* store specific handles for futher control */ - if(g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) - { - /* FIXIT : first value will be overwritten if there's more - * than 1 demuxer/parser - */ - debug_log("plugged element is demuxer. take it\n"); - mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX; - mainbin[MMPLAYER_M_DEMUX].gst = new_element; - - /*Added for multi audio support */ - if(g_strrstr(klass, "Demux")) - { - mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX; - mainbin[MMPLAYER_M_DEMUX_EX].gst = new_element; - - /* NOTE : workaround for bug in mpegtsdemux since doesn't emit - no-more-pad signal. this may cause wrong content attributes at PAUSED state - this code should be removed after mpegtsdemux is fixed */ - if ( g_strrstr(GST_OBJECT_NAME(factory), "mpegtsdemux") ) - { - debug_warning("force no-more-pad to TRUE since mpegtsdemux os not giving no-more-pad signal. content attributes may wrong"); - player->no_more_pad = TRUE; - } - } - if (g_strrstr(name_to_plug, "asfdemux")) // to support trust-zone only - { - g_object_set(mainbin[MMPLAYER_M_DEMUX_EX].gst, "file-location", player->profile.uri,NULL); - } - } - else if(g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player,pad)) - { - if(mainbin[MMPLAYER_M_DEC1].gst == NULL) - { - debug_log("plugged element is decoder. take it[MMPLAYER_M_DEC1]\n"); - mainbin[MMPLAYER_M_DEC1].id = MMPLAYER_M_DEC1; - mainbin[MMPLAYER_M_DEC1].gst = new_element; - } - else if(mainbin[MMPLAYER_M_DEC2].gst == NULL) - { - debug_log("plugged element is decoder. take it[MMPLAYER_M_DEC2]\n"); - mainbin[MMPLAYER_M_DEC2].id = MMPLAYER_M_DEC2; - mainbin[MMPLAYER_M_DEC2].gst = new_element; - } - /* NOTE : IF one codec is found, add it to supported_codec and remove from - * missing plugin. Both of them are used to check what's supported codec - * before returning result of play start. And, missing plugin should be - * updated here for multi track files. - */ - if(g_str_has_prefix(mime, "video")) - { - GstPad *src_pad = NULL; - GstPadTemplate *pad_templ = NULL; - GstCaps *caps = NULL; - gchar *caps_str = NULL; - - debug_log("found VIDEO decoder\n"); - player->not_supported_codec &= MISSING_PLUGIN_AUDIO; - player->can_support_codec |= FOUND_PLUGIN_VIDEO; - - src_pad = gst_element_get_static_pad (new_element, "src"); - pad_templ = gst_pad_get_pad_template (src_pad); - caps = GST_PAD_TEMPLATE_CAPS(pad_templ); - - caps_str = gst_caps_to_string(caps); - - /* clean */ - MMPLAYER_FREEIF( caps_str ); - gst_object_unref (src_pad); - } - else if (g_str_has_prefix(mime, "audio")) - { - debug_log("found AUDIO decoder\n"); - player->not_supported_codec &= MISSING_PLUGIN_VIDEO; - player->can_support_codec |= FOUND_PLUGIN_AUDIO; - } - } - - if ( ! __mmplayer_close_link(player, pad, new_element, - name_template,gst_element_factory_get_static_pad_templates(factory)) ) - { - MMPLAYER_FREEIF(name_template); - if (player->keep_detecting_vcodec) - continue; - - /* Link is failed even though a supportable codec is found. */ - __mmplayer_check_not_supported_codec(player, klass, mime); - - debug_error("failed to call _close_link\n"); - return FALSE; - } - - MMPLAYER_FREEIF(name_template); - return TRUE; - } - - gst_caps_unref(res); - break; - } - } - - /* There is no available codec. */ - __mmplayer_check_not_supported_codec(player, klass, mime); - - MMPLAYER_FLEAVE(); - return FALSE; - -ERROR: - /* release */ - if ( queue ) - gst_object_unref( queue ); - - if ( queue_pad ) - gst_object_unref( queue_pad ); - - if ( element ) - gst_object_unref ( element ); - - return FALSE; -} - - -static int -__mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime) -{ - MMPLAYER_FENTER(); - - return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail ( mime, MM_ERROR_INVALID_ARGUMENT ); - - debug_log("class : %s, mime : %s \n", factory_class, mime ); - - /* add missing plugin */ - /* NOTE : msl should check missing plugin for image mime type. - * Some motion jpeg clips can have playable audio track. - * So, msl have to play audio after displaying popup written video format not supported. - */ - if ( !( player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst ) ) - { - if ( !( player->can_support_codec | player->videodec_linked | player->audiodec_linked ) ) - { - debug_log("not found demuxer\n"); - player->not_found_demuxer = TRUE; - player->unlinked_demuxer_mime = g_strdup_printf ( "%s", mime ); - - goto DONE; - } - } - - if( !g_strrstr(factory_class, "Demuxer")) - { - if( ( g_str_has_prefix(mime, "video") ) ||( g_str_has_prefix(mime, "image") ) ) - { - debug_log("can support codec=%d, vdec_linked=%d, adec_linked=%d\n", - player->can_support_codec, player->videodec_linked, player->audiodec_linked); - - /* check that clip have multi tracks or not */ - if ( ( player->can_support_codec & FOUND_PLUGIN_VIDEO ) && ( player->videodec_linked ) ) - { - debug_log("video plugin is already linked\n"); - } - else - { - debug_warning("add VIDEO to missing plugin\n"); - player->not_supported_codec |= MISSING_PLUGIN_VIDEO; - } - } - else if ( g_str_has_prefix(mime, "audio") ) - { - if ( ( player->can_support_codec & FOUND_PLUGIN_AUDIO ) && ( player->audiodec_linked ) ) - { - debug_log("audio plugin is already linked\n"); - } - else - { - debug_warning("add AUDIO to missing plugin\n"); - player->not_supported_codec |= MISSING_PLUGIN_AUDIO; - } - } - } - -DONE: - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - - -static void -__mmplayer_pipeline_complete(GstElement *decodebin, gpointer data) -{ - mm_player_t* player = (mm_player_t*)data; - - MMPLAYER_FENTER(); - - return_if_fail( player ); - - /* remove fakesink. */ - if ( !__mmplayer_gst_remove_fakesink( player, - &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]) ) - { - /* NOTE : __mmplayer_pipeline_complete() can be called several time. because - * signaling mechanism ( pad-added, no-more-pad, new-decoded-pad ) from various - * source element are not same. To overcome this situation, this function will called - * several places and several times. Therefore, this is not an error case. - */ - return; - } - - debug_log("pipeline has completely constructed\n"); - - if (( player->ini.async_start ) && - ( player->msg_posted == FALSE ) && - ( player->cmd >= MMPLAYER_COMMAND_START )) - { - __mmplayer_handle_missed_plugin( player ); - } - - MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-complete" ); -} - -static gboolean -__mmplayer_verify_next_play_path(mm_player_t *player) -{ - MMHandleType attrs = 0; - MMPlayerParseProfile profile; - gint uri_idx = 0, check_cnt = 0; - char *uri = NULL; - gint mode = MM_PLAYER_PD_MODE_NONE; - gint count = 0; - guint num_of_list = 0; - - MMPLAYER_FENTER(); - - debug_log("checking for gapless play"); - - if (player->pipeline->textbin) - { - debug_error("subtitle path is enabled. gapless play is not supported.\n"); - goto ERROR; - } - - attrs = MMPLAYER_GET_ATTRS(player); - if ( !attrs ) - { - debug_error("fail to get attributes.\n"); - goto ERROR; - } - - /* seamless playback is supported in case of audio only */ - mm_attrs_get_int_by_name(attrs, "content_video_found", &mode); - if (mode) - { - debug_log("video found"); - goto ERROR; - } - - if (mm_attrs_get_int_by_name (attrs, "pd_mode", &mode) == MM_ERROR_NONE) - { - if (mode == TRUE) - { - debug_warning("pd mode\n"); - goto ERROR; - } - } - - if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE) - { - debug_error("can not get play count\n"); - } - - num_of_list = g_list_length(player->uri_info.uri_list); - - debug_log("repeat count = %d, num_of_list = %d\n", count, num_of_list); - - if ( num_of_list == 0 ) - { - if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) - { - debug_error("can not get profile_uri\n"); - goto ERROR; - } - - if (!uri) - { - debug_error("uri list is empty.\n"); - goto ERROR; - } - - player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri)); - debug_log("add original path : %s ", uri); - - num_of_list = 1; - uri= NULL; - } - - uri_idx = player->uri_info.uri_idx; - - while(TRUE) - { - check_cnt++; - - if (check_cnt > num_of_list) - { - debug_error("there is no valid uri."); - goto ERROR; - } - - debug_log("uri idx : %d / %d\n", uri_idx, num_of_list); - - if ( uri_idx < num_of_list-1 ) - { - uri_idx++; - } - else - { - if ((count <= 1) && (count != -1)) - { - debug_log("no repeat."); - goto ERROR; - } - else if ( count > 1 ) /* decrease play count */ - { - /* we successeded to rewind. update play count and then wait for next EOS */ - count--; - - mm_attrs_set_int_by_name(attrs, "profile_play_count", count); - - /* commit attribute */ - if ( mmf_attrs_commit ( attrs ) ) - { - debug_error("failed to commit attribute\n"); - } - } - - /* count < 0 : repeat continually */ - uri_idx = 0; - } - - uri = g_list_nth_data(player->uri_info.uri_list, uri_idx); - debug_log("uri idx : %d, uri = %s\n", uri_idx, uri); - - if (uri == NULL) - { - debug_warning("next uri does not exist\n"); - continue; - } - - if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) - { - debug_error("failed to parse profile\n"); - continue; - } - - if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) && - (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) - { - debug_warning("uri type is not supported (%d).", profile.uri_type); - continue; - } - - break; - } - - player->uri_info.uri_idx = uri_idx; - mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri); - - - if (mmf_attrs_commit(player->attrs)) - { - debug_error("failed to commit.\n"); - goto ERROR; - } - - debug_log("next uri %s (%d)\n", uri, uri_idx); - - return TRUE; - -ERROR: - - debug_error("unable to play next path. EOS will be posted soon.\n"); - return FALSE; -} - -static void -__mmplayer_initialize_next_play(mm_player_t *player) -{ - int i; - - MMPLAYER_FENTER(); - - player->smooth_streaming = FALSE; - player->videodec_linked = 0; - player->audiodec_linked = 0; - player->videosink_linked = 0; - player->audiosink_linked = 0; - player->textsink_linked = 0; - player->is_external_subtitle_present = FALSE; - player->not_supported_codec = MISSING_PLUGIN_NONE; - player->can_support_codec = FOUND_PLUGIN_NONE; - player->pending_seek.is_pending = FALSE; - player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME; - player->pending_seek.pos = 0; - player->msg_posted = FALSE; - player->has_many_types = FALSE; - player->no_more_pad = FALSE; - player->is_drm_file = FALSE; - player->not_found_demuxer = 0; - player->doing_seek = FALSE; - player->max_audio_channels = 0; - player->is_subtitle_force_drop = FALSE; - player->play_subtitle = FALSE; - player->use_textoverlay = FALSE; - player->adjust_subtitle_pos = 0; - - player->updated_bitrate_count = 0; - player->total_bitrate = 0; - player->updated_maximum_bitrate_count = 0; - player->total_maximum_bitrate = 0; - - _mmplayer_track_initialize(player); - - for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) - { - player->bitrate[i] = 0; - player->maximum_bitrate[i] = 0; - } - - if (player->v_stream_caps) - { - gst_caps_unref(player->v_stream_caps); - player->v_stream_caps = NULL; - } - - mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0); - mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0); - - /* clean found parsers */ - if (player->parsers) - { - GList *parsers = player->parsers; - for ( ;parsers ; parsers = g_list_next(parsers)) - { - gchar *name = parsers->data; - MMPLAYER_FREEIF(name); - } - g_list_free(player->parsers); - player->parsers = NULL; - } - - /* clean found audio decoders */ - if (player->audio_decoders) - { - GList *a_dec = player->audio_decoders; - for ( ;a_dec ; a_dec = g_list_next(a_dec)) - { - gchar *name = a_dec->data; - MMPLAYER_FREEIF(name); - } - g_list_free(player->audio_decoders); - player->audio_decoders = NULL; - } - - MMPLAYER_FLEAVE(); -} - -static void -__mmplayer_activate_next_source(mm_player_t *player, GstState target) -{ - MMPlayerGstElement *mainbin = NULL; - MMMessageParamType msg_param = {0,}; - GstElement *element = NULL; - MMHandleType attrs = 0; - char *uri = NULL; - enum MainElementID elemId = MMPLAYER_M_NUM; - - MMPLAYER_FENTER(); - - if ((player == NULL) || - (player->pipeline == NULL) || - (player->pipeline->mainbin == NULL)) - { - debug_error("player is null.\n"); - goto ERROR; - } - - mainbin = player->pipeline->mainbin; - msg_param.code = MM_ERROR_PLAYER_INTERNAL; - - attrs = MMPLAYER_GET_ATTRS(player); - if ( !attrs ) - { - debug_error("fail to get attributes.\n"); - goto ERROR; - } - - /* Initialize Player values */ - __mmplayer_initialize_next_play(player); - - mm_attrs_get_string_by_name(attrs, "profile_uri", &uri); - - if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) - { - debug_error("failed to parse profile\n"); - msg_param.code = MM_ERROR_PLAYER_INVALID_URI; - goto ERROR; - } - - if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) || - (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) - { - debug_error("it's dash or hls. not support."); - msg_param.code = MM_ERROR_PLAYER_INVALID_URI; - goto ERROR; - } - - /* setup source */ - switch ( player->profile.uri_type ) - { - /* file source */ - case MM_PLAYER_URI_TYPE_FILE: - { - debug_log("using filesrc for 'file://' handler.\n"); - - element = gst_element_factory_make("filesrc", "source"); - - if ( !element ) - { - debug_error("failed to create filesrc\n"); - break; - } - - g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */ - break; - } - case MM_PLAYER_URI_TYPE_URL_HTTP: - { - gchar *user_agent, *proxy, *cookies, **cookie_list; - gint http_timeout = DEFAULT_HTTP_TIMEOUT; - user_agent = proxy = cookies = NULL; - cookie_list = NULL; - - element = gst_element_factory_make(player->ini.name_of_httpsrc, "http_streaming_source"); - if ( !element ) - { - debug_error("failed to create http streaming source element[%s].\n", player->ini.name_of_httpsrc); - break; - } - debug_log("using http streamming source [%s].\n", player->ini.name_of_httpsrc); - - /* get attribute */ - mm_attrs_get_string_by_name ( attrs, "streaming_cookie", &cookies ); - mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent ); - mm_attrs_get_string_by_name ( attrs, "streaming_proxy", &proxy ); - mm_attrs_get_int_by_name ( attrs, "streaming_timeout", &http_timeout ); - - if ((http_timeout == DEFAULT_HTTP_TIMEOUT) && - (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) - { - debug_log("get timeout from ini\n"); - http_timeout = player->ini.http_timeout; - } - - /* get attribute */ - secure_debug_log("location : %s\n", player->profile.uri); - secure_debug_log("cookies : %s\n", cookies); - secure_debug_log("proxy : %s\n", proxy); - secure_debug_log("user_agent : %s\n", user_agent); - debug_log("timeout : %d\n", http_timeout); - - /* setting property to streaming source */ - g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL); - g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL); - g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL); - - /* check if prosy is vailid or not */ - if ( util_check_valid_url ( proxy ) ) - g_object_set(G_OBJECT(element), "proxy", proxy, NULL); - /* parsing cookies */ - if ( ( cookie_list = util_get_cookie_list ((const char*)cookies) ) ) - g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL); - if ( user_agent ) - g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL); - break; - } - default: - debug_error("not support uri type %d\n", player->profile.uri_type); - break; - } - - if ( !element ) - { - debug_error("no source element was created.\n"); - goto ERROR; - } - - if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) - { - debug_error("failed to add source element to pipeline\n"); - gst_object_unref(GST_OBJECT(element)); - element = NULL; - goto ERROR; - } - - /* take source element */ - mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC; - mainbin[MMPLAYER_M_SRC].gst = element; - - element = NULL; - - if (MMPLAYER_IS_HTTP_STREAMING(player)) - { - if (player->streamer == NULL) - { - player->streamer = __mm_player_streaming_create(); - __mm_player_streaming_initialize(player->streamer); - } - - elemId = MMPLAYER_M_TYPEFIND; - element = gst_element_factory_make("typefind", "typefinder"); - MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", - G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player ); - } - else - { - elemId = MMPLAYER_M_AUTOPLUG; - element = __mmplayer_create_decodebin(player); - } - - /* check autoplug element is OK */ - if ( ! element ) - { - debug_error("can not create element (%d)\n", elemId); - goto ERROR; - } - - if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) - { - debug_error("failed to add sinkbin to pipeline\n"); - gst_object_unref(GST_OBJECT(element)); - element = NULL; - goto ERROR; - } - - mainbin[elemId].id = elemId; - mainbin[elemId].gst = element; - - if ( gst_element_link (mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE ) - { - debug_error("Failed to link src - autoplug (or typefind)\n"); - goto ERROR; - } - - if (gst_element_set_state (mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) - { - debug_error("Failed to change state of src element\n"); - goto ERROR; - } - - if (!MMPLAYER_IS_HTTP_STREAMING(player)) - { - if (gst_element_set_state (mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) - { - debug_error("Failed to change state of decodebin\n"); - goto ERROR; - } - } - else - { - if (gst_element_set_state (mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) - { - debug_error("Failed to change state of src element\n"); - goto ERROR; - } - } - - player->gapless.stream_changed = TRUE; - player->gapless.running = TRUE; - MMPLAYER_FLEAVE(); - return; - -ERROR: - MMPLAYER_PLAYBACK_UNLOCK(player); - - if (!player->msg_posted) - { - MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param); - player->msg_posted = TRUE; - } - return; -} - -static gboolean -__mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type) -{ - mm_player_selector_t *selector = &player->selector[type]; - MMPlayerGstElement *sinkbin = NULL; - enum MainElementID selectorId = MMPLAYER_M_NUM; - enum MainElementID sinkId = MMPLAYER_M_NUM; - GstPad *srcpad = NULL; - GstPad *sinkpad = NULL; - - MMPLAYER_FENTER(); - return_val_if_fail (player, FALSE); - - debug_log("type %d", type); - - switch (type) - { - case MM_PLAYER_TRACK_TYPE_AUDIO: - selectorId = MMPLAYER_M_A_INPUT_SELECTOR; - sinkId = MMPLAYER_A_BIN; - sinkbin = player->pipeline->audiobin; - break; - case MM_PLAYER_TRACK_TYPE_TEXT: - selectorId = MMPLAYER_M_T_INPUT_SELECTOR; - sinkId = MMPLAYER_T_BIN; - sinkbin = player->pipeline->textbin; - break; - default: - debug_error("requested type is not supportable"); - return FALSE; - break; - } - - if (player->pipeline->mainbin[selectorId].gst) - { - gint n; - - srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src"); - - if (selector->event_probe_id != 0) - gst_pad_remove_probe (srcpad, selector->event_probe_id); - selector->event_probe_id = 0; - - if ((sinkbin) && (sinkbin[sinkId].gst)) - { - sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink"); - - if (srcpad && sinkpad) - { - /* after getting drained signal there is no data flows, so no need to do pad_block */ - debug_log("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad)); - gst_pad_unlink (srcpad, sinkpad); - } - - gst_object_unref (sinkpad); - sinkpad = NULL; - } - gst_object_unref (srcpad); - srcpad = NULL; - - debug_log("selector release"); - - /* release and unref requests pad from the selector */ - for (n = 0; n < selector->channels->len; n++) - { - GstPad *sinkpad = g_ptr_array_index (selector->channels, n); - gst_element_release_request_pad ((player->pipeline->mainbin[selectorId].gst), sinkpad); - } - g_ptr_array_set_size (selector->channels, 0); - - gst_element_set_state (player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL); - gst_bin_remove (GST_BIN_CAST (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst); - - player->pipeline->mainbin[selectorId].gst = NULL; - selector = NULL; - } - - return TRUE; -} - -static void -__mmplayer_deactivate_old_path(mm_player_t *player) -{ - MMPLAYER_FENTER(); - return_if_fail ( player ); - - if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) || - (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) - { - debug_error("deactivate selector error"); - goto ERROR; - } - - _mmplayer_track_destroy(player); - __mmplayer_release_signal_connection( player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG ); - - if (player->streamer) - { - __mm_player_streaming_deinitialize (player->streamer); - __mm_player_streaming_destroy(player->streamer); - player->streamer = NULL; - } - - MMPLAYER_PLAYBACK_LOCK(player); - g_cond_signal( &player->next_play_thread_cond ); - - MMPLAYER_FLEAVE(); - return; - -ERROR: - - if (!player->msg_posted) - { - MMMessageParamType msg = {0,}; - - /*post error*/ - msg.code = MM_ERROR_PLAYER_INTERNAL; - debug_error("next_uri_play> deactivate error"); - - MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg); - player->msg_posted = TRUE; - } - return; -} - -int _mmplayer_set_uri(MMHandleType hplayer, const char* uri) -{ - int result = MM_ERROR_NONE; - mm_player_t* player = (mm_player_t*) hplayer; - MMPLAYER_FENTER(); - - return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri); - if (mmf_attrs_commit(player->attrs)) - { - debug_error("failed to commit the original uri.\n"); - result = MM_ERROR_PLAYER_INTERNAL; - } - else - { - if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE) - { - debug_error("failed to add the original uri in the uri list.\n"); - } - } - - MMPLAYER_FLEAVE(); - return result; -} - -int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path) -{ - mm_player_t* player = (mm_player_t*) hplayer; - guint num_of_list = 0; - - MMPLAYER_FENTER(); - - return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail (uri, MM_ERROR_INVALID_ARGUMENT); - - if (player->pipeline && player->pipeline->textbin) - { - debug_error("subtitle path is enabled.\n"); - return MM_ERROR_PLAYER_INVALID_STATE; - } - - num_of_list = g_list_length(player->uri_info.uri_list); - - if (is_first_path == TRUE) - { - if (num_of_list == 0) - { - player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri)); - debug_log("add original path : %s", uri); - } - else - { - player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0)); - player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0); - - debug_log("change original path : %s", uri); - } - } - else - { - if (num_of_list == 0) - { - MMHandleType attrs = 0; - char *original_uri = NULL; - - attrs = MMPLAYER_GET_ATTRS(player); - if ( attrs ) - { - mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri); - - if (!original_uri) - { - debug_error("there is no original uri."); - return MM_ERROR_PLAYER_INVALID_STATE; - } - - player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri)); - player->uri_info.uri_idx = 0; - - debug_log("add original path at first : %s (%d)", original_uri); - } - } - - player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri)); - debug_log("add new path : %s (total num of list = %d)", uri, g_list_length(player->uri_info.uri_list)); - } - - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; -} - -int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri) -{ - mm_player_t* player = (mm_player_t*) hplayer; - char *next_uri = NULL; - guint num_of_list = 0; - - MMPLAYER_FENTER(); - return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - num_of_list = g_list_length(player->uri_info.uri_list); - - if (num_of_list > 0) - { - gint uri_idx = player->uri_info.uri_idx; - - if ( uri_idx < num_of_list-1 ) - uri_idx++; - else - uri_idx = 0; - - next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx); - debug_error("next uri idx : %d, uri = %s\n", uri_idx, next_uri); - - *uri = g_strdup(next_uri); - } - - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; -} - -static void -__mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, -GstCaps *caps, gpointer data) -{ - mm_player_t* player = (mm_player_t*)data; - const gchar* klass = NULL; - const gchar* mime = NULL; - gchar* caps_str = NULL; - - klass = gst_element_factory_get_metadata (gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS); - mime = gst_structure_get_name (gst_caps_get_structure(caps, 0)); - caps_str = gst_caps_to_string(caps); - - debug_warning("unknown type of caps : %s from %s", - caps_str, GST_ELEMENT_NAME (elem)); - - MMPLAYER_FREEIF(caps_str); - - /* There is no available codec. */ - __mmplayer_check_not_supported_codec (player, klass, mime); -} - -static gboolean -__mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, -GstCaps * caps, gpointer data) -{ - mm_player_t* player = (mm_player_t*)data; - const char* mime = NULL; - gboolean ret = TRUE; - - MMPLAYER_LOG_GST_CAPS_TYPE(caps); - mime = gst_structure_get_name (gst_caps_get_structure(caps, 0)); - - if (g_str_has_prefix(mime, "audio")) { - GstStructure* caps_structure = NULL; - gint samplerate = 0; - gint channels = 0; - gchar *caps_str = NULL; - - caps_structure = gst_caps_get_structure(caps, 0); - gst_structure_get_int (caps_structure, "rate", &samplerate); - gst_structure_get_int (caps_structure, "channels", &channels); - - if ( (channels > 0 && samplerate == 0)) { - debug_log("exclude audio..."); - ret = FALSE; - } - - caps_str = gst_caps_to_string(caps); - /* set it directly because not sent by TAG */ - if (g_strrstr(caps_str, "mobile-xmf")) { - mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf"); - } - MMPLAYER_FREEIF (caps_str); - } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) { - debug_log("already video linked"); - ret = FALSE; - } else { - debug_log("found new stream"); - } - - return ret; -} - -static gint -__mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, -GstCaps* caps, GstElementFactory* factory, gpointer data) -{ - /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed - We are defining our own and will be removed when it actually exposed */ - typedef enum { - GST_AUTOPLUG_SELECT_TRY, - GST_AUTOPLUG_SELECT_EXPOSE, - GST_AUTOPLUG_SELECT_SKIP - } GstAutoplugSelectResult; - - GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY; - mm_player_t* player = (mm_player_t*)data; - - gchar* factory_name = NULL; - gchar* caps_str = NULL; - const gchar* klass = NULL; - gint idx = 0; - - factory_name = GST_OBJECT_NAME (factory); - klass = gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS); - caps_str = gst_caps_to_string(caps); - -// debug_log("found new element [%s] to link for caps [%s]", factory_name, caps_str); - debug_log("found new element [%s] to link", factory_name); - - /* store type string */ - if (player->type == NULL) - { - player->type = gst_caps_to_string(caps); - __mmplayer_update_content_type_info(player); - } - - /* filtering exclude keyword */ - for ( idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++ ) - { - if ( strstr(factory_name, player->ini.exclude_element_keyword[idx] ) ) - { - debug_warning("skipping [%s] by exculde keyword [%s]\n", - factory_name, player->ini.exclude_element_keyword[idx] ); - - // NOTE : does we need to check n_value against the number of item selected? - result = GST_AUTOPLUG_SELECT_SKIP; - goto DONE; - } - } - - /* check factory class for filtering */ - /* NOTE : msl don't need to use image plugins. - * So, those plugins should be skipped for error handling. - */ - if (g_strrstr(klass, "Codec/Decoder/Image")) - { - debug_log("skipping [%s] by not required\n", factory_name); - result = GST_AUTOPLUG_SELECT_SKIP; - goto DONE; - } - - if ((MMPLAYER_IS_ES_BUFF_SRC(player)) && - (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) - { - // TO CHECK : subtitle if needed, add subparse exception. - debug_log("skipping parser/demuxer [%s] in es player by not required\n", factory_name); - result = GST_AUTOPLUG_SELECT_SKIP; - goto DONE; - } - - if (g_strrstr(factory_name, "mpegpsdemux")) - { - debug_log("skipping PS container - not support\n"); - result = GST_AUTOPLUG_SELECT_SKIP; - goto DONE; - } - - if (g_strrstr(factory_name, SMOOTH_STREAMING_DEMUX)) - player->smooth_streaming = TRUE; - - /* check ALP Codec can be used or not */ - if ((g_strrstr(klass, "Codec/Decoder/Audio"))) - { - GstStructure* str = NULL; - gint channels = 0; - - str = gst_caps_get_structure( caps, 0 ); - if ( str ) - { - gst_structure_get_int (str, "channels", &channels); - - debug_log ("check audio ch : %d %d\n", player->max_audio_channels, channels); - if (player->max_audio_channels < channels) - { - player->max_audio_channels = channels; - } - } - - if (!player->audiodec_linked) - { - /* set stream information */ - __mmplayer_set_audio_attrs (player, caps); - } - } - else if ((g_strrstr(klass, "Codec/Decoder/Video"))) - { - if (g_strrstr(factory_name, "omx_")) - { - char *env = getenv ("MM_PLAYER_HW_CODEC_DISABLE"); - if (env != NULL) - { - if (strncasecmp(env, "yes", 3) == 0) - { - debug_log ("skipping [%s] by disabled\n", factory_name); - result = GST_AUTOPLUG_SELECT_SKIP; - goto DONE; - } - } - } - } - - if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) || - (g_strrstr(klass, "Codec/Decoder/Video"))) - { - gint stype = 0; - gint width = 0; - GstStructure *str = NULL; - mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype); - - /* don't make video because of not required */ - if (stype == MM_DISPLAY_SURFACE_NULL) - { - debug_log ("no video because it's not required. -> return expose"); - if (player->set_mode.media_packet_video_stream == FALSE) - { - result = GST_AUTOPLUG_SELECT_EXPOSE; - goto DONE; - } - } - - /* get w/h for omx state-tune */ - str = gst_caps_get_structure (caps, 0); - gst_structure_get_int (str, "width", &width); - - if (width != 0) { - if (player->v_stream_caps) { - gst_caps_unref(player->v_stream_caps); - player->v_stream_caps = NULL; - } - - player->v_stream_caps = gst_caps_copy(caps); - debug_log ("take caps for video state tune"); - MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps); - } - } - - if (g_strrstr(klass, "Decoder")) - { - const char* mime = NULL; - mime = gst_structure_get_name (gst_caps_get_structure(caps, 0)); - - if (g_str_has_prefix(mime, "video")) - { - // __mmplayer_check_video_zero_cpoy(player, factory); - - player->not_supported_codec &= MISSING_PLUGIN_AUDIO; - player->can_support_codec |= FOUND_PLUGIN_VIDEO; - - player->videodec_linked = 1; - } - else if(g_str_has_prefix(mime, "audio")) - { - player->not_supported_codec &= MISSING_PLUGIN_VIDEO; - player->can_support_codec |= FOUND_PLUGIN_AUDIO; - - player->audiodec_linked = 1; - } - } - -DONE: - MMPLAYER_FREEIF(caps_str); - - return result; -} - - -#if 0 -static GValueArray* -__mmplayer_gst_decode_autoplug_factories(GstElement *bin, GstPad* pad, -GstCaps * caps, gpointer data) -{ - //mm_player_t* player = (mm_player_t*)data; - - debug_log("decodebin is requesting factories for caps [%s] from element[%s]", - gst_caps_to_string(caps), - GST_ELEMENT_NAME(GST_PAD_PARENT(pad))); - - return NULL; -} -#endif - -static void -__mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, -gpointer data) // @ -{ - //mm_player_t* player = (mm_player_t*)data; - GstCaps* caps = NULL; - - debug_log("[Decodebin2] pad-removed signal\n"); - - caps = gst_pad_query_caps(new_pad, NULL); - if (caps) - { - gchar* caps_str = NULL; - caps_str = gst_caps_to_string(caps); - - debug_log("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem) ); - - MMPLAYER_FREEIF(caps_str); - } -} - -static void -__mmplayer_gst_decode_drained(GstElement *bin, gpointer data) -{ - mm_player_t* player = (mm_player_t*)data; - - MMPLAYER_FENTER(); - return_if_fail ( player ); - - debug_log("__mmplayer_gst_decode_drained"); - - if (player->use_deinterleave == TRUE) - { - debug_log("group playing mode."); - return; - } - - if (!g_mutex_trylock(&player->cmd_lock)) - { - debug_warning("Fail to get cmd lock"); - return; - } - - if (!__mmplayer_verify_next_play_path(player)) - { - debug_log("decoding is finished."); - player->gapless.running = FALSE; - player->gapless.start_time = 0; - g_mutex_unlock(&player->cmd_lock); - return; - } - - player->gapless.reconfigure = TRUE; - - /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/ - __mmplayer_deactivate_old_path(player); - - g_mutex_unlock(&player->cmd_lock); - - MMPLAYER_FLEAVE(); -} - -static void -__mmplayer_gst_element_added (GstElement *bin, GstElement *element, gpointer data) -{ - mm_player_t* player = (mm_player_t*)data; - const gchar* klass = NULL; - gchar* factory_name = NULL; - - klass = gst_element_factory_get_metadata (gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS); - factory_name = GST_OBJECT_NAME (gst_element_get_factory(element)); - - debug_log("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element)); - - if (__mmplayer_add_dump_buffer_probe(player, element)) - debug_log("add buffer probe"); - - //<- - if (g_strrstr(klass, "Codec/Decoder/Audio")) - { - gchar* selected = NULL; - selected = g_strdup( GST_ELEMENT_NAME(element)); - player->audio_decoders = g_list_append (player->audio_decoders, selected); - } - //-> temp code - - if (g_strrstr(klass, "Parser")) - { - gchar* selected = NULL; - - selected = g_strdup (factory_name); - player->parsers = g_list_append (player->parsers, selected); - } - - if ((g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) && !(g_strrstr(klass, "Adaptive"))) - { - /* FIXIT : first value will be overwritten if there's more - * than 1 demuxer/parser - */ - - //debug_log ("plugged element is demuxer. take it\n"); - player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX; - player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element; - - /*Added for multi audio support */ // Q. del? - if (g_strrstr(klass, "Demux")) - { - player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX; - player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element; - } - } - - if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) - { - int surface_type = 0; - - mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type); - -#if 0 // this is for 0.10 plugin with downstream modification - /* playback protection if drm file */ - if (player->use_video_stream || surface_type == MM_DISPLAY_SURFACE_EVAS || surface_type == MM_DISPLAY_SURFACE_X_EXT) - { - debug_log("playback can be protected if playready drm"); - g_object_set (G_OBJECT(element), "playback-protection", TRUE, NULL); - } -#endif - } - - // to support trust-zone only - if (g_strrstr(factory_name, "asfdemux")) - { - debug_log ("set file-location %s\n", player->profile.uri); - g_object_set (G_OBJECT(element), "file-location", player->profile.uri, NULL); - - if (player->video_hub_download_mode == TRUE) - { - g_object_set (G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL); - } - } - else if (g_strrstr(factory_name, "legacyh264parse")) // SMOOTH_STREAMING_DEMUX - { - debug_log ("[%s] output-format to legacyh264parse\n", SMOOTH_STREAMING_DEMUX); - g_object_set (G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */ - } - else if (g_strrstr(factory_name, "mpegaudioparse")) - { - if ((MMPLAYER_IS_HTTP_STREAMING(player)) && - (__mmplayer_is_only_mp3_type(player->type))) - { - debug_log ("[mpegaudioparse] set streaming pull mode."); - g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL); - } - } - else if (g_strrstr(factory_name, "omx")) - { - if (g_strrstr(klass, "Codec/Decoder/Video")) - { - gboolean ret = FALSE; - - if (player->v_stream_caps != NULL) - { - GstPad *pad = gst_element_get_static_pad(element, "sink"); - - if (pad) - { - ret = gst_pad_set_caps(pad, player->v_stream_caps); - debug_log("found omx decoder, setting gst_pad_set_caps for omx (ret:%d)", ret); - MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps); - gst_object_unref (pad); - } - } - g_object_set (G_OBJECT(element), "state-tuning", TRUE, NULL); - } -#ifdef _MM_PLAYER_ALP_PARSER - if (g_strrstr(factory_name, "omx_mp3dec")) - { - g_list_foreach (player->parsers, check_name, player); - } -#endif - player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element; - } - - if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) && - (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) - { - debug_log ("plugged element is multiqueue. take it\n"); - - player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER; - player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element; - - if ((MMPLAYER_IS_HTTP_STREAMING(player)) || - (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))) - { - /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/ - __mm_player_streaming_set_multiqueue(player->streamer, - element, - TRUE, - player->ini.http_buffering_time, - 1.0, - player->ini.http_buffering_limit); - - __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst); - } - } - - MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-added" ); - return; -} - -static gboolean __mmplayer_configure_audio_callback(mm_player_t* player) -{ - MMPLAYER_FENTER(); - return_val_if_fail ( player, FALSE ); - - if ( MMPLAYER_IS_STREAMING(player) ) - return FALSE; - - /* This callback can be set to music player only. */ - if((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) - { - debug_warning("audio callback is not supported for video"); - return FALSE; - } - - if (player->audio_stream_cb) - { - { - GstPad *pad = NULL; - - pad = gst_element_get_static_pad (player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink"); - - if ( !pad ) - { - debug_error("failed to get sink pad from audiosink to probe data\n"); - return FALSE; - } - player->audio_cb_probe_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, - __mmplayer_audio_stream_probe, player, NULL); - - gst_object_unref (pad); - - pad = NULL; - } - } - else - { - debug_error("There is no audio callback to configure.\n"); - return FALSE; - } - - MMPLAYER_FLEAVE(); - - return TRUE; -} - -static void -__mmplayer_init_factories(mm_player_t* player) // @ -{ - return_if_fail ( player ); - - player->factories = gst_registry_feature_filter(gst_registry_get(), - (GstPluginFeatureFilter)__mmplayer_feature_filter, FALSE, NULL); - player->factories = g_list_sort(player->factories, (GCompareFunc)util_factory_rank_compare); -} - -static void -__mmplayer_release_factories(mm_player_t* player) // @ -{ - MMPLAYER_FENTER(); - return_if_fail ( player ); - - if (player->factories) - { - gst_plugin_feature_list_free (player->factories); - player->factories = NULL; - } - - MMPLAYER_FLEAVE(); -} - -static void -__mmplayer_release_misc(mm_player_t* player) -{ - int i; - gboolean cur_mode = player->set_mode.rich_audio; - MMPLAYER_FENTER(); - - return_if_fail ( player ); - - player->use_video_stream = FALSE; - player->video_stream_cb = NULL; - player->video_stream_cb_user_param = NULL; - - player->audio_stream_cb = NULL; - player->audio_stream_render_cb_ex = NULL; - player->audio_stream_cb_user_param = NULL; - player->audio_stream_sink_sync = false; - - player->video_stream_changed_cb = NULL; - player->video_stream_changed_cb_user_param = NULL; - - player->audio_stream_changed_cb = NULL; - player->audio_stream_changed_cb_user_param = NULL; - - player->sent_bos = FALSE; - player->playback_rate = DEFAULT_PLAYBACK_RATE; - - player->doing_seek = FALSE; - - player->updated_bitrate_count = 0; - player->total_bitrate = 0; - player->updated_maximum_bitrate_count = 0; - player->total_maximum_bitrate = 0; - - player->not_found_demuxer = 0; - - player->last_position = 0; - player->duration = 0; - player->http_content_size = 0; - player->not_supported_codec = MISSING_PLUGIN_NONE; - player->can_support_codec = FOUND_PLUGIN_NONE; - player->pending_seek.is_pending = FALSE; - player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME; - player->pending_seek.pos = 0; - player->msg_posted = FALSE; - player->has_many_types = FALSE; - player->is_drm_file = FALSE; - player->max_audio_channels = 0; - player->video_share_api_delta = 0; - player->video_share_clock_delta = 0; - player->sound_focus.keep_last_pos = FALSE; - player->sound_focus.acquired = FALSE; - player->is_subtitle_force_drop = FALSE; - player->play_subtitle = FALSE; - player->use_textoverlay = FALSE; - player->adjust_subtitle_pos = 0; - player->last_multiwin_status = FALSE; - player->has_closed_caption = FALSE; - player->set_mode.media_packet_video_stream = FALSE; - memset(&player->set_mode, 0, sizeof(MMPlayerSetMode)); - /* recover mode */ - player->set_mode.rich_audio = cur_mode; - - for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) - { - player->bitrate[i] = 0; - player->maximum_bitrate[i] = 0; - } - - /* remove media stream cb (appsrc cb) */ - for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) - { - player->media_stream_buffer_status_cb[i] = NULL; - player->media_stream_seek_data_cb[i] = NULL; - } - - /* free memory related to audio effect */ - MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin); - - if (player->state_tune_caps) - { - gst_caps_unref(player->state_tune_caps); - player->state_tune_caps = NULL; - } - - if (player->video_cb_probe_id) - { - GstPad *pad = NULL; - - pad = gst_element_get_static_pad (player->video_fakesink, "sink"); - - if (pad) { - debug_log("release video probe\n"); - - /* release audio callback */ - gst_pad_remove_probe (pad, player->video_cb_probe_id); - player->video_cb_probe_id = 0; - player->video_stream_cb = NULL; - player->video_stream_cb_user_param = NULL; - } - } - - MMPLAYER_FLEAVE(); -} - -static void -__mmplayer_release_misc_post(mm_player_t* player) -{ - char *original_uri = NULL; - MMPLAYER_FENTER(); - - /* player->pipeline is already released before. */ - - return_if_fail ( player ); - - mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0); - mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0); - - /* clean found parsers */ - if (player->parsers) - { - GList *parsers = player->parsers; - for ( ;parsers ; parsers = g_list_next(parsers)) - { - gchar *name = parsers->data; - MMPLAYER_FREEIF(name); - } - g_list_free(player->parsers); - player->parsers = NULL; - } - - /* clean found audio decoders */ - if (player->audio_decoders) - { - GList *a_dec = player->audio_decoders; - for ( ;a_dec ; a_dec = g_list_next(a_dec)) - { - gchar *name = a_dec->data; - MMPLAYER_FREEIF(name); - } - g_list_free(player->audio_decoders); - player->audio_decoders = NULL; - } - - /* clean the uri list except original uri */ - if (player->uri_info.uri_list) - { - original_uri = g_list_nth_data(player->uri_info.uri_list, 0); - - if (player->attrs) - { - mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri); - debug_log("restore original uri = %s\n", original_uri); - - if (mmf_attrs_commit(player->attrs)) - { - debug_error("failed to commit the original uri.\n"); - } - } - - GList *uri_list = player->uri_info.uri_list; - for ( ;uri_list ; uri_list = g_list_next(uri_list)) - { - gchar *uri = uri_list->data; - MMPLAYER_FREEIF(uri); - } - g_list_free(player->uri_info.uri_list); - player->uri_info.uri_list = NULL; - } - - player->uri_info.uri_idx = 0; - MMPLAYER_FLEAVE(); -} - -static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name) -{ - GstElement *element = NULL; - GstPad *sinkpad; - - debug_log("creating %s to plug\n", name); - - element = gst_element_factory_make(name, NULL); - if ( ! element ) - { - debug_error("failed to create queue\n"); - return NULL; - } - - if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY) ) - { - debug_error("failed to set state READY to %s\n", name); - gst_object_unref (element); - return NULL; - } - - if ( ! gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) - { - debug_error("failed to add %s\n", name); - gst_object_unref (element); - return NULL; - } - - sinkpad = gst_element_get_static_pad(element, "sink"); - - if ( GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad) ) - { - debug_error("failed to link %s\n", name); - gst_object_unref (sinkpad); - gst_object_unref (element); - return NULL; - } - - debug_log("linked %s to pipeline successfully\n", name); - - gst_object_unref (sinkpad); - - return element; -} - -static gboolean -__mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement, -const char *padname, const GList *templlist) -{ - GstPad *pad = NULL; - gboolean has_dynamic_pads = FALSE; - gboolean has_many_types = FALSE; - const char *klass = NULL; - GstStaticPadTemplate *padtemplate = NULL; - GstElementFactory *factory = NULL; - GstElement* queue = NULL; - GstElement* parser = NULL; - GstPad *pssrcpad = NULL; - GstPad *qsrcpad = NULL, *qsinkpad = NULL; - MMPlayerGstElement *mainbin = NULL; - GstStructure* str = NULL; - GstCaps* srccaps = NULL; - GstState target_state = GST_STATE_READY; - gboolean isvideo_decoder = FALSE; - guint q_max_size_time = 0; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player && - player->pipeline && - player->pipeline->mainbin, - FALSE ); - - mainbin = player->pipeline->mainbin; - - debug_log("plugging pad %s:%s to newly create %s:%s\n", - GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad ) ), - GST_PAD_NAME( srcpad ), - GST_ELEMENT_NAME( sinkelement ), - padname); - - factory = gst_element_get_factory(sinkelement); - klass = gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS); - - /* check if player can do start continually */ - MMPLAYER_CHECK_CMD_IF_EXIT(player); - - /* need it to warm up omx before linking to pipeline */ - if (g_strrstr(GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad ) ), "demux")) - { - debug_log("get demux caps.\n"); - if (player->state_tune_caps) - { - gst_caps_unref(player->state_tune_caps); - player->state_tune_caps = NULL; - } - player->state_tune_caps = gst_caps_copy(gst_pad_get_current_caps(srcpad)); - } - - /* NOTE : OMX Codec can check if resource is available or not at this state. */ - if (g_strrstr(GST_ELEMENT_NAME(sinkelement), "omx")) - { - if (player->state_tune_caps != NULL) - { - debug_log("set demux's caps to omx codec if resource is available"); - if (gst_pad_set_caps(gst_element_get_static_pad(sinkelement, "sink"), player->state_tune_caps)) - { - target_state = GST_STATE_PAUSED; - isvideo_decoder = TRUE; - g_object_set(G_OBJECT(sinkelement), "state-tuning", TRUE, NULL); - } - else - { - debug_warning("failed to set caps for state tuning"); - } - } - gst_caps_unref(player->state_tune_caps); - player->state_tune_caps = NULL; - } - - if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, target_state) ) - { - debug_error("failed to set %d state to %s\n", target_state, GST_ELEMENT_NAME( sinkelement )); - if (isvideo_decoder) - { - gst_element_set_state(sinkelement, GST_STATE_NULL); - gst_object_unref(G_OBJECT(sinkelement)); - player->keep_detecting_vcodec = TRUE; - } - goto ERROR; - } - - /* add to pipeline */ - if ( ! gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), sinkelement) ) - { - debug_error("failed to add %s to mainbin\n", GST_ELEMENT_NAME( sinkelement )); - goto ERROR; - } - - debug_log("element klass : %s\n", klass); - - /* added to support multi track files */ - /* only decoder case and any of the video/audio still need to link*/ - if(g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player,srcpad)) - { - gchar *name = g_strdup(GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad ))); - - if (g_strrstr(name, "mpegtsdemux")|| g_strrstr(name, SMOOTH_STREAMING_DEMUX)) - { - gchar *src_demux_caps_str = NULL; - gchar *needed_parser = NULL; - GstCaps *src_demux_caps = NULL; - gboolean smooth_streaming = FALSE; - - src_demux_caps = gst_pad_query_caps(srcpad, NULL); - src_demux_caps_str = gst_caps_to_string(src_demux_caps); - - gst_caps_unref(src_demux_caps); - - if (g_strrstr(src_demux_caps_str, "video/x-h264")) - { - if (g_strrstr(name, SMOOTH_STREAMING_DEMUX)) - { - needed_parser = g_strdup("legacyh264parse"); - smooth_streaming = TRUE; - } - else - { - needed_parser = g_strdup("h264parse"); - } - } - else if (g_strrstr(src_demux_caps_str, "video/mpeg")) - { - needed_parser = g_strdup("mpeg4videoparse"); - } - MMPLAYER_FREEIF(src_demux_caps_str); - - if (needed_parser) - { - parser = __mmplayer_element_create_and_link(player, srcpad, needed_parser); - MMPLAYER_FREEIF(needed_parser); - - if ( !parser ) - { - debug_error("failed to create parser\n"); - } - else - { - if (smooth_streaming) - { - g_object_set (parser, "output-format", 1, NULL); /* NALU/Byte Stream format */ - } - - /* update srcpad if parser is created */ - pssrcpad = gst_element_get_static_pad(parser, "src"); - srcpad = pssrcpad; - } - } - } - MMPLAYER_FREEIF(name); - - queue = __mmplayer_element_create_and_link(player, srcpad, "queue"); // parser - queue or demuxer - queue - if ( ! queue ) - { - debug_error("failed to create queue\n"); - goto ERROR; - } - - /* update srcpad to link with decoder */ - qsrcpad = gst_element_get_static_pad(queue, "src"); - srcpad = qsrcpad; - - q_max_size_time = GST_QUEUE_DEFAULT_TIME; - - /* assigning queue handle for futher manipulation purpose */ - /* FIXIT : make it some kind of list so that msl can support more then two stream (text, data, etc...) */ - if(mainbin[MMPLAYER_M_Q1].gst == NULL) - { - mainbin[MMPLAYER_M_Q1].id = MMPLAYER_M_Q1; - mainbin[MMPLAYER_M_Q1].gst = queue; - - if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) - { - g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-time", 0 , NULL); - g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-buffers", 2, NULL); - g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-bytes", 0, NULL); - } - else - { - if (!MMPLAYER_IS_RTSP_STREAMING(player)) - g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL); - } - } - else if(mainbin[MMPLAYER_M_Q2].gst == NULL) - { - mainbin[MMPLAYER_M_Q2].id = MMPLAYER_M_Q2; - mainbin[MMPLAYER_M_Q2].gst = queue; - - if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) - { - g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-time", 0 , NULL); - g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-buffers", 2, NULL); - g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-bytes", 0, NULL); - } - else - { - if (!MMPLAYER_IS_RTSP_STREAMING(player)) - g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL); - } - } - else - { - debug_error("Not supporting more then two elementary stream\n"); - g_assert(1); - } - - pad = gst_element_get_static_pad(sinkelement, padname); - - if ( ! pad ) - { - debug_warning("failed to get pad(%s) from %s. retrying with [sink]\n", - padname, GST_ELEMENT_NAME(sinkelement) ); - - pad = gst_element_get_static_pad(sinkelement, "sink"); - if ( ! pad ) - { - debug_error("failed to get pad(sink) from %s. \n", - GST_ELEMENT_NAME(sinkelement) ); - goto ERROR; - } - } - - /* to check the video/audio type set the proper flag*/ - const gchar *mime_type = NULL; - { - srccaps = gst_pad_query_caps(srcpad, NULL); - if ( !srccaps ) - goto ERROR; - - str = gst_caps_get_structure( srccaps, 0 ); - if ( ! str ) - goto ERROR; - - mime_type = gst_structure_get_name(str); - if ( ! mime_type ) - goto ERROR; - } - - /* link queue and decoder. so, it will be queue - decoder. */ - if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, pad) ) - { - gst_object_unref(GST_OBJECT(pad)); - debug_error("failed to link (%s) to pad(%s)\n", GST_ELEMENT_NAME( sinkelement ), padname ); - - /* reconstitute supportable codec */ - if (strstr(mime_type, "video")) - { - player->can_support_codec ^= FOUND_PLUGIN_VIDEO; - } - else if (strstr(mime_type, "audio")) - { - player->can_support_codec ^= FOUND_PLUGIN_AUDIO; - } - goto ERROR; - } - - if (strstr(mime_type, "video")) - { - player->videodec_linked = 1; - debug_msg("player->videodec_linked set to 1\n"); - - } - else if (strstr(mime_type, "audio")) - { - player->audiodec_linked = 1; - debug_msg("player->auddiodec_linked set to 1\n"); - } - - gst_object_unref(GST_OBJECT(pad)); - gst_caps_unref(GST_CAPS(srccaps)); - srccaps = NULL; - } - - if ( !MMPLAYER_IS_HTTP_PD(player) ) - { - if( (g_strrstr(klass, "Demux") && !g_strrstr(klass, "Metadata")) || (g_strrstr(klass, "Parser") ) ) - { - if (MMPLAYER_IS_HTTP_STREAMING(player)) - { - gint64 dur_bytes = 0L; - gchar *file_buffering_path = NULL; - gboolean use_file_buffer = FALSE; - - if ( !mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) - { - debug_log("creating http streaming buffering queue\n"); - - queue = gst_element_factory_make("queue2", "queue2"); - if ( ! queue ) - { - debug_error ( "failed to create buffering queue element\n" ); - goto ERROR; - } - - if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY) ) - { - debug_error("failed to set state READY to buffering queue\n"); - goto ERROR; - } - - if ( !gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue) ) - { - debug_error("failed to add buffering queue\n"); - goto ERROR; - } - - qsinkpad = gst_element_get_static_pad(queue, "sink"); - qsrcpad = gst_element_get_static_pad(queue, "src"); - - if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, qsinkpad) ) - { - debug_error("failed to link buffering queue\n"); - goto ERROR; - } - srcpad = qsrcpad; - - - mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER; - mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue; - - if ( !MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) - { - if ( !gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes)) - debug_error("fail to get duration.\n"); - - if (dur_bytes > 0) - { - use_file_buffer = MMPLAYER_USE_FILE_FOR_BUFFERING(player); - file_buffering_path = g_strdup(player->ini.http_file_buffer_path); - } - else - { - dur_bytes = 0; - } - } - - /* NOTE : we cannot get any duration info from ts container in case of streaming */ - if(!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux")) - { - __mm_player_streaming_set_queue2(player->streamer, - queue, - TRUE, - player->ini.http_max_size_bytes, - player->ini.http_buffering_time, - 1.0, - player->ini.http_buffering_limit, - use_file_buffer, - file_buffering_path, - (guint64)dur_bytes); - } - - MMPLAYER_FREEIF(file_buffering_path); - } - } - } - } - /* if it is not decoder or */ - /* in decoder case any of the video/audio still need to link*/ - if(!g_strrstr(klass, "Decoder")) - { - - pad = gst_element_get_static_pad(sinkelement, padname); - if ( ! pad ) - { - debug_warning("failed to get pad(%s) from %s. retrying with [sink]\n", - padname, GST_ELEMENT_NAME(sinkelement) ); - - pad = gst_element_get_static_pad(sinkelement, "sink"); - - if ( ! pad ) - { - debug_error("failed to get pad(sink) from %s. \n", - GST_ELEMENT_NAME(sinkelement) ); - goto ERROR; - } - } - - if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, pad) ) - { - gst_object_unref(GST_OBJECT(pad)); - debug_error("failed to link (%s) to pad(%s)\n", GST_ELEMENT_NAME( sinkelement ), padname ); - goto ERROR; - } - - gst_object_unref(GST_OBJECT(pad)); - } - - for(;templlist != NULL; templlist = templlist->next) - { - padtemplate = templlist->data; - - debug_log ("director = [%d], presence = [%d]\n", padtemplate->direction, padtemplate->presence); - - if( padtemplate->direction != GST_PAD_SRC || - padtemplate->presence == GST_PAD_REQUEST ) - continue; - - switch(padtemplate->presence) - { - case GST_PAD_ALWAYS: - { - GstPad *srcpad = gst_element_get_static_pad(sinkelement, "src"); - GstCaps *caps = gst_pad_query_caps(srcpad, NULL); - - /* Check whether caps has many types */ - if ( !gst_caps_is_fixed(caps)) - { - debug_log ("always pad but, caps has many types"); - MMPLAYER_LOG_GST_CAPS_TYPE(caps); - has_many_types = TRUE; - break; - } - - if ( ! __mmplayer_try_to_plug(player, srcpad, caps) ) - { - gst_object_unref(GST_OBJECT(srcpad)); - gst_caps_unref(GST_CAPS(caps)); - - debug_error("failed to plug something after %s\n", GST_ELEMENT_NAME( sinkelement )); - goto ERROR; - } - - gst_caps_unref(GST_CAPS(caps)); - gst_object_unref(GST_OBJECT(srcpad)); - - } - break; - - - case GST_PAD_SOMETIMES: - has_dynamic_pads = TRUE; - break; - - default: - break; - } - } - - /* check if player can do start continually */ - MMPLAYER_CHECK_CMD_IF_EXIT(player); - - if( has_dynamic_pads ) - { - player->have_dynamic_pad = TRUE; - MMPLAYER_SIGNAL_CONNECT ( player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", - G_CALLBACK(__mmplayer_add_new_pad), player); - - /* for streaming, more then one typefind will used for each elementary stream - * so this doesn't mean the whole pipeline completion - */ - if ( ! MMPLAYER_IS_RTSP_STREAMING( player ) ) - { - MMPLAYER_SIGNAL_CONNECT( player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", - G_CALLBACK(__mmplayer_pipeline_complete), player); - } - } - - if (has_many_types) - { - GstPad *pad = NULL; - - player->has_many_types = has_many_types; - - pad = gst_element_get_static_pad(sinkelement, "src"); - MMPLAYER_SIGNAL_CONNECT (player, pad, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "notify::caps", G_CALLBACK(__mmplayer_add_new_caps), player); - gst_object_unref (GST_OBJECT(pad)); - } - - - /* check if player can do start continually */ - MMPLAYER_CHECK_CMD_IF_EXIT(player); - - if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, GST_STATE_PAUSED) ) - { - debug_error("failed to set state PAUSED to %s\n", GST_ELEMENT_NAME( sinkelement )); - goto ERROR; - } - - if ( queue ) - { - if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (queue, GST_STATE_PAUSED) ) - { - debug_error("failed to set state PAUSED to queue\n"); - goto ERROR; - } - - queue = NULL; - - gst_object_unref (GST_OBJECT(qsrcpad)); - qsrcpad = NULL; - } - - if ( parser ) - { - if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (parser, GST_STATE_PAUSED) ) - { - debug_error("failed to set state PAUSED to queue\n"); - goto ERROR; - } - - parser = NULL; - - gst_object_unref (GST_OBJECT(pssrcpad)); - pssrcpad = NULL; - } - - MMPLAYER_FLEAVE(); - - return TRUE; - -ERROR: - - if ( queue ) - { - gst_object_unref(GST_OBJECT(qsrcpad)); - - /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state. - * You need to explicitly set elements to the NULL state before - * dropping the final reference, to allow them to clean up. - */ - gst_element_set_state(queue, GST_STATE_NULL); - /* And, it still has a parent "player". - * You need to let the parent manage the object instead of unreffing the object directly. - */ - - gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue); - //gst_object_unref( queue ); - } - - if ( srccaps ) - gst_caps_unref(GST_CAPS(srccaps)); - - return FALSE; -} - -static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data) // @ -{ - const gchar *klass; - //const gchar *name; - - /* we only care about element factories */ - if (!GST_IS_ELEMENT_FACTORY(feature)) - return FALSE; - - /* only parsers, demuxers and decoders */ - klass = gst_element_factory_get_metadata (GST_ELEMENT_FACTORY(feature), GST_ELEMENT_METADATA_KLASS); - //name = gst_element_factory_get_longname(GST_ELEMENT_FACTORY(feature)); - - if( g_strrstr(klass, "Demux") == NULL && - g_strrstr(klass, "Codec/Decoder") == NULL && - g_strrstr(klass, "Depayloader") == NULL && - g_strrstr(klass, "Parse") == NULL) - { - return FALSE; - } - return TRUE; -} - - -static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data) -{ - mm_player_t* player = (mm_player_t*) data; - GstCaps *caps = NULL; - GstStructure *str = NULL; - const char *name; - - MMPLAYER_FENTER(); - - return_if_fail ( pad ) - return_if_fail ( unused ) - return_if_fail ( data ) - - caps = gst_pad_query_caps(pad, NULL); - if ( !caps ) - return; - - str = gst_caps_get_structure(caps, 0); - if ( !str ) - return; - - name = gst_structure_get_name(str); - if ( !name ) - return; - debug_log("name=%s\n", name); - - if ( ! __mmplayer_try_to_plug(player, pad, caps) ) - { - debug_error("failed to autoplug for type (%s)\n", name); - gst_caps_unref(caps); - return; - } - - gst_caps_unref(caps); - - __mmplayer_pipeline_complete( NULL, (gpointer)player ); - - MMPLAYER_FLEAVE(); - - return; -} - -static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps) -{ - GstStructure *str; - gint version = 0; - const char *stream_type; - gchar *version_field = NULL; - - MMPLAYER_FENTER(); - - return_if_fail ( player ); - return_if_fail ( caps ); - - str = gst_caps_get_structure(caps, 0); - if ( !str ) - return; - - stream_type = gst_structure_get_name(str); - if ( !stream_type ) - return; - - - /* set unlinked mime type for downloadable codec */ - if (g_str_has_prefix(stream_type, "video/")) - { - if (g_str_has_prefix(stream_type, "video/mpeg")) - { - gst_structure_get_int (str, MM_PLAYER_MPEG_VNAME, &version); - version_field = MM_PLAYER_MPEG_VNAME; - } - else if (g_str_has_prefix(stream_type, "video/x-wmv")) - { - gst_structure_get_int (str, MM_PLAYER_WMV_VNAME, &version); - version_field = MM_PLAYER_WMV_VNAME; - - } - else if (g_str_has_prefix(stream_type, "video/x-divx")) - { - gst_structure_get_int (str, MM_PLAYER_DIVX_VNAME, &version); - version_field = MM_PLAYER_DIVX_VNAME; - } - - if (version) - { - player->unlinked_video_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version); - } - else - { - player->unlinked_video_mime = g_strdup_printf("%s", stream_type); - } - } - else if (g_str_has_prefix(stream_type, "audio/")) - { - if (g_str_has_prefix(stream_type, "audio/mpeg")) // mp3 or aac - { - gst_structure_get_int (str, MM_PLAYER_MPEG_VNAME, &version); - version_field = MM_PLAYER_MPEG_VNAME; - } - else if (g_str_has_prefix(stream_type, "audio/x-wma")) - { - gst_structure_get_int (str, MM_PLAYER_WMA_VNAME, &version); - version_field = MM_PLAYER_WMA_VNAME; - } - - if (version) - { - player->unlinked_audio_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version); - } - else - { - player->unlinked_audio_mime = g_strdup_printf("%s", stream_type); - } - } - - MMPLAYER_FLEAVE(); -} - -static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data) -{ - mm_player_t* player = (mm_player_t*) data; - GstCaps *caps = NULL; - GstStructure *str = NULL; - const char *name; - - MMPLAYER_FENTER(); - return_if_fail ( player ); - return_if_fail ( pad ); - - GST_OBJECT_LOCK (pad); - if ((caps = gst_pad_get_current_caps(pad))) - gst_caps_ref(caps); - GST_OBJECT_UNLOCK (pad); - - if ( NULL == caps ) - { - caps = gst_pad_query_caps(pad, NULL); - if ( !caps ) return; - } - - MMPLAYER_LOG_GST_CAPS_TYPE(caps); - - str = gst_caps_get_structure(caps, 0); - if ( !str ) - return; - - name = gst_structure_get_name(str); - if ( !name ) - return; - - player->num_dynamic_pad++; - debug_log("stream count inc : %d\n", player->num_dynamic_pad); - - /* Note : If the stream is the subtitle, we try not to play it. Just close the demuxer subtitle pad. - * If want to play it, remove this code. - */ - if (g_strrstr(name, "application")) - { - if (g_strrstr(name, "x-id3") || g_strrstr(name, "x-apetag")) - { - /* If id3/ape tag comes, keep going */ - debug_log("application mime exception : id3/ape tag"); - } - else - { - /* Otherwise, we assume that this stream is subtile. */ - debug_log(" application mime type pad is closed."); - return; - } - } - else if (g_strrstr(name, "audio")) - { - gint samplerate = 0, channels = 0; - - if (player->audiodec_linked) - { - gst_caps_unref(caps); - debug_log("multi tracks. skip to plug"); - return; - } - - /* set stream information */ - /* if possible, set it here because the caps is not distrubed by resampler. */ - gst_structure_get_int (str, "rate", &samplerate); - mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate); - - gst_structure_get_int (str, "channels", &channels); - mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels); - - debug_log("audio samplerate : %d channels : %d", samplerate, channels); - } - else if (g_strrstr(name, "video")) - { - gint stype; - mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype); - - /* don't make video because of not required */ - if (stype == MM_DISPLAY_SURFACE_NULL) - { - debug_log("no video because it's not required"); - return; - } - - player->v_stream_caps = gst_caps_copy(caps); //if needed, video caps is required when videobin is created - } - - if ( ! __mmplayer_try_to_plug(player, pad, caps) ) - { - debug_error("failed to autoplug for type (%s)", name); - - __mmplayer_set_unlinked_mime_type(player, caps); - } - - gst_caps_unref(caps); - - MMPLAYER_FLEAVE(); - return; -} - -gboolean -__mmplayer_dump_pipeline_state( mm_player_t* player ) -{ - GstIterator*iter = NULL; - gboolean done = FALSE; - - GValue item = {0, }; - GstElement *element = NULL; - GstElementFactory *factory = NULL; - - GstState state = GST_STATE_VOID_PENDING; - GstState pending = GST_STATE_VOID_PENDING; - GstClockTime time = 200*GST_MSECOND; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player && - player->pipeline && - player->pipeline->mainbin, - FALSE ); - - iter = gst_bin_iterate_recurse(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) ); - - if ( iter != NULL ) - { - while (!done) { - switch ( gst_iterator_next (iter, &item) ) - { - case GST_ITERATOR_OK: - element = g_value_get_object(&item); - gst_element_get_state(element,&state, &pending,time); - - factory = gst_element_get_factory (element) ; - if (factory) - { - debug_error("%s:%s : From:%s To:%s refcount : %d\n", GST_OBJECT_NAME(factory) , GST_ELEMENT_NAME(element) , - gst_element_state_get_name(state), gst_element_state_get_name(pending) , GST_OBJECT_REFCOUNT_VALUE(element)); - } - g_value_reset (&item); - break; - case GST_ITERATOR_RESYNC: - gst_iterator_resync (iter); - break; - case GST_ITERATOR_ERROR: - done = TRUE; - break; - case GST_ITERATOR_DONE: - done = TRUE; - break; - } - } - } - - element = GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst); - - gst_element_get_state(element,&state, &pending,time); - - factory = gst_element_get_factory (element) ; - - if (factory) - { - debug_error("%s:%s : From:%s To:%s refcount : %d\n", - GST_OBJECT_NAME(factory), - GST_ELEMENT_NAME(element), - gst_element_state_get_name(state), - gst_element_state_get_name(pending), - GST_OBJECT_REFCOUNT_VALUE(element) ); - } - - g_value_unset(&item); - - if ( iter ) - gst_iterator_free (iter); - - MMPLAYER_FLEAVE(); - - return FALSE; -} - - -gboolean -__mmplayer_check_subtitle( mm_player_t* player ) -{ - MMHandleType attrs = 0; - char *subtitle_uri = NULL; - - MMPLAYER_FENTER(); - - return_val_if_fail( player, FALSE ); - - /* get subtitle attribute */ - attrs = MMPLAYER_GET_ATTRS(player); - if ( !attrs ) - return FALSE; - - mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri); - if ( !subtitle_uri || !strlen(subtitle_uri)) - return FALSE; - - debug_log ("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri)); - player->is_external_subtitle_present = TRUE; - - MMPLAYER_FLEAVE(); - - return TRUE; -} - -static gboolean -__mmplayer_can_extract_pcm( mm_player_t* player ) -{ - MMHandleType attrs = 0; - gboolean is_drm = FALSE; - gboolean sound_extraction = FALSE; - - return_val_if_fail ( player, FALSE ); - - attrs = MMPLAYER_GET_ATTRS(player); - if ( !attrs ) - { - debug_error("fail to get attributes."); - return FALSE; - } - - /* check file is drm or not */ - if (g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm")) - g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm", &is_drm, NULL); - - /* get sound_extraction property */ - mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction); - - if ( ! sound_extraction || is_drm ) - { - debug_log("checking pcm extraction mode : %d, drm : %d", sound_extraction, is_drm); - return FALSE; - } - - return TRUE; -} - -static gboolean -__mmplayer_handle_gst_error ( mm_player_t* player, GstMessage * message, GError* error ) -{ - MMMessageParamType msg_param; - gchar *msg_src_element; - - MMPLAYER_FENTER(); - - return_val_if_fail( player, FALSE ); - return_val_if_fail( error, FALSE ); - - /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */ - - memset (&msg_param, 0, sizeof(MMMessageParamType)); - - if ( error->domain == GST_CORE_ERROR ) - { - msg_param.code = __gst_handle_core_error( player, error->code ); - } - else if ( error->domain == GST_LIBRARY_ERROR ) - { - msg_param.code = __gst_handle_library_error( player, error->code ); - } - else if ( error->domain == GST_RESOURCE_ERROR ) - { - msg_param.code = __gst_handle_resource_error( player, error->code ); - } - else if ( error->domain == GST_STREAM_ERROR ) - { - msg_param.code = __gst_handle_stream_error( player, error, message ); - } - else - { - debug_warning("This error domain is not defined.\n"); - - /* we treat system error as an internal error */ - msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM; - } - - if ( message->src ) - { - msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( message->src ) ); - - msg_param.data = (void *) error->message; - - debug_error("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]\n", - msg_src_element, g_quark_to_string (error->domain), error->message, error->code, msg_param.code); - } - - /* no error */ - if (msg_param.code == MM_ERROR_NONE) - return TRUE; - - /* post error to application */ - if ( ! player->msg_posted ) - { - MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param ); - /* don't post more if one was sent already */ - player->msg_posted = TRUE; - } - else - { - debug_log("skip error post because it's sent already.\n"); - } - - MMPLAYER_FLEAVE(); - - return TRUE; -} - -static gboolean -__mmplayer_handle_streaming_error ( mm_player_t* player, GstMessage * message ) -{ - debug_log("\n"); - MMMessageParamType msg_param; - gchar *msg_src_element = NULL; - GstStructure *s = NULL; - guint error_id = 0; - gchar *error_string = NULL; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, FALSE ); - return_val_if_fail ( message, FALSE ); - - s = malloc( sizeof(GstStructure) ); - memcpy ( s, gst_message_get_structure ( message ), sizeof(GstStructure)); - - if ( !gst_structure_get_uint (s, "error_id", &error_id) ) - error_id = MMPLAYER_STREAMING_ERROR_NONE; - - switch ( error_id ) - { - case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO: - msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO; - break; - case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO: - msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO; - break; - case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL: - msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL; - break; - case MMPLAYER_STREAMING_ERROR_DNS_FAIL: - msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL; - break; - case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED; - break; - case MMPLAYER_STREAMING_ERROR_BAD_SERVER: - msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER; - break; - case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL: - msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL; - break; - case MMPLAYER_STREAMING_ERROR_INVALID_URL: - msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL; - break; - case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG: - msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG; - break; - case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES: - msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES; - break; - case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT: - msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT; - break; - case MMPLAYER_STREAMING_ERROR_BAD_REQUEST: - msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST; - break; - case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED; - break; - case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED; - break; - case MMPLAYER_STREAMING_ERROR_FORBIDDEN: - msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN; - break; - case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND: - msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND; - break; - case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED; - break; - case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE: - msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE; - break; - case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED; - break; - case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT: - msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT; - break; - case MMPLAYER_STREAMING_ERROR_GONE: - msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE; - break; - case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED; - break; - case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED; - break; - case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE: - msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE; - break; - case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE: - msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE; - break; - case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE: - msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE; - break; - case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD: - msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD; - break; - case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND: - msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND; - break; - case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH: - msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH; - break; - case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID: - msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID; - break; - case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE: - msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE; - break; - case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE: - msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE; - break; - case MMPLAYER_STREAMING_ERROR_INVALID_RANGE: - msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE; - break; - case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY: - msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY; - break; - case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED; - break; - case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED; - break; - case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT: - msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT; - break; - case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE: - msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE; - break; - case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR: - msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR; - break; - case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED; - break; - case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY: - msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY; - break; - case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE: - msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE; - break; - case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT: - msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT; - break; - case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED; - break; - case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED: - msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED; - break; - default: - { - MMPLAYER_FREEIF(s); - return MM_ERROR_PLAYER_STREAMING_FAIL; - } - } - - error_string = g_strdup(gst_structure_get_string (s, "error_string")); - if ( error_string ) - msg_param.data = (void *) error_string; - - if ( message->src ) - { - msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( message->src ) ); - - debug_error("-Msg src : [%s] Code : [%x] Error : [%s] \n", - msg_src_element, msg_param.code, (char*)msg_param.data ); - } - - /* post error to application */ - if ( ! player->msg_posted ) - { - MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param ); - - /* don't post more if one was sent already */ - player->msg_posted = TRUE; - } - else - { - debug_log("skip error post because it's sent already.\n"); - } - - MMPLAYER_FREEIF(s); - MMPLAYER_FLEAVE(); - g_free(error_string); - - return TRUE; - -} - -static gint -__gst_handle_core_error( mm_player_t* player, int code ) -{ - gint trans_err = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - switch ( code ) - { - case GST_CORE_ERROR_MISSING_PLUGIN: - return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT; - case GST_CORE_ERROR_STATE_CHANGE: - case GST_CORE_ERROR_SEEK: - case GST_CORE_ERROR_NOT_IMPLEMENTED: - case GST_CORE_ERROR_FAILED: - case GST_CORE_ERROR_TOO_LAZY: - case GST_CORE_ERROR_PAD: - case GST_CORE_ERROR_THREAD: - case GST_CORE_ERROR_NEGOTIATION: - case GST_CORE_ERROR_EVENT: - case GST_CORE_ERROR_CAPS: - case GST_CORE_ERROR_TAG: - case GST_CORE_ERROR_CLOCK: - case GST_CORE_ERROR_DISABLED: - default: - trans_err = MM_ERROR_PLAYER_INVALID_STREAM; - break; - } - - MMPLAYER_FLEAVE(); - - return trans_err; -} - -static gint -__gst_handle_library_error( mm_player_t* player, int code ) -{ - gint trans_err = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - switch ( code ) - { - case GST_LIBRARY_ERROR_FAILED: - case GST_LIBRARY_ERROR_TOO_LAZY: - case GST_LIBRARY_ERROR_INIT: - case GST_LIBRARY_ERROR_SHUTDOWN: - case GST_LIBRARY_ERROR_SETTINGS: - case GST_LIBRARY_ERROR_ENCODE: - default: - trans_err = MM_ERROR_PLAYER_INVALID_STREAM; - break; - } - - MMPLAYER_FLEAVE(); - - return trans_err; -} - - -static gint -__gst_handle_resource_error( mm_player_t* player, int code ) -{ - gint trans_err = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - switch ( code ) - { - case GST_RESOURCE_ERROR_NO_SPACE_LEFT: - trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE; - break; - case GST_RESOURCE_ERROR_NOT_FOUND: - case GST_RESOURCE_ERROR_OPEN_READ: - if ( MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING ( player ) - || MMPLAYER_IS_RTSP_STREAMING(player)) - { - trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL; - break; - } - case GST_RESOURCE_ERROR_READ: - if ( MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING ( player ) - || MMPLAYER_IS_RTSP_STREAMING(player)) - { - trans_err = MM_ERROR_PLAYER_STREAMING_FAIL; - break; - } - case GST_RESOURCE_ERROR_WRITE: - case GST_RESOURCE_ERROR_FAILED: - case GST_RESOURCE_ERROR_SEEK: - case GST_RESOURCE_ERROR_TOO_LAZY: - case GST_RESOURCE_ERROR_BUSY: - case GST_RESOURCE_ERROR_OPEN_WRITE: - case GST_RESOURCE_ERROR_OPEN_READ_WRITE: - case GST_RESOURCE_ERROR_CLOSE: - case GST_RESOURCE_ERROR_SYNC: - case GST_RESOURCE_ERROR_SETTINGS: - default: - trans_err = MM_ERROR_PLAYER_INTERNAL; - break; - } - - MMPLAYER_FLEAVE(); - - return trans_err; -} - - -static gint -__gst_handle_stream_error( mm_player_t* player, GError* error, GstMessage * message ) -{ - gint trans_err = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - return_val_if_fail( error, MM_ERROR_INVALID_ARGUMENT ); - return_val_if_fail ( message, MM_ERROR_INVALID_ARGUMENT ); - - switch ( error->code ) - { - case GST_STREAM_ERROR_FAILED: - case GST_STREAM_ERROR_TYPE_NOT_FOUND: - case GST_STREAM_ERROR_DECODE: - case GST_STREAM_ERROR_WRONG_TYPE: - case GST_STREAM_ERROR_DECRYPT: - case GST_STREAM_ERROR_DECRYPT_NOKEY: - case GST_STREAM_ERROR_CODEC_NOT_FOUND: - trans_err = __gst_transform_gsterror( player, message, error ); - break; - - case GST_STREAM_ERROR_NOT_IMPLEMENTED: - case GST_STREAM_ERROR_TOO_LAZY: - case GST_STREAM_ERROR_ENCODE: - case GST_STREAM_ERROR_DEMUX: - case GST_STREAM_ERROR_MUX: - case GST_STREAM_ERROR_FORMAT: - default: - trans_err = MM_ERROR_PLAYER_INVALID_STREAM; - break; - } - - MMPLAYER_FLEAVE(); - - return trans_err; -} - -/* NOTE : decide gstreamer state whether there is some playable track or not. */ -static gint -__gst_transform_gsterror( mm_player_t* player, GstMessage * message, GError* error ) -{ - gchar *src_element_name = NULL; - GstElement *src_element = NULL; - GstElementFactory *factory = NULL; - const gchar* klass = NULL; - - MMPLAYER_FENTER(); - - /* FIXIT */ - return_val_if_fail ( message, MM_ERROR_INVALID_ARGUMENT ); - return_val_if_fail ( message->src, MM_ERROR_INVALID_ARGUMENT ); - return_val_if_fail ( error, MM_ERROR_INVALID_ARGUMENT ); - - src_element = GST_ELEMENT_CAST(message->src); - if ( !src_element ) - goto INTERNAL_ERROR; - - src_element_name = GST_ELEMENT_NAME(src_element); - if ( !src_element_name ) - goto INTERNAL_ERROR; - - factory = gst_element_get_factory(src_element); - if ( !factory ) - goto INTERNAL_ERROR; - - klass = gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS); - if ( !klass ) - goto INTERNAL_ERROR; - - debug_log("error code=%d, msg=%s, src element=%s, class=%s\n", - error->code, error->message, src_element_name, klass); - - //<- - { - if (player->selector) { - int msg_src_pos = 0; - gint active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index; - debug_log ("current active pad index -%d", active_pad_index); - - if (src_element_name) { - int idx = 0; - - if (player->audio_decoders) { - GList *adec = player->audio_decoders; - for ( ;adec ; adec = g_list_next(adec)) { - gchar *name = adec->data; - - debug_log("found audio decoder name = %s", name); - if (g_strrstr(name, src_element_name)) { - msg_src_pos = idx; - break; - } - idx++; - } - } - debug_log("active pad = %d, error src index = %d", active_pad_index, msg_src_pos); - } - - if (active_pad_index != msg_src_pos) { - debug_log("skip error because error is posted from no activated track"); - return MM_ERROR_NONE; - } - } - } - //-> temp code - - switch ( error->code ) - { - case GST_STREAM_ERROR_DECODE: - { - /* Demuxer can't parse one track because it's corrupted. - * So, the decoder for it is not linked. - * But, it has one playable track. - */ - if ( g_strrstr(klass, "Demux") ) - { - if ( player->can_support_codec == FOUND_PLUGIN_VIDEO ) - { - return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND; - } - else if ( player->can_support_codec == FOUND_PLUGIN_AUDIO ) - { - return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND; - } - else - { - if ( player->pipeline->audiobin ) // PCM - { - return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND; - } - else - { - goto CODEC_NOT_FOUND; - } - } - } - return MM_ERROR_PLAYER_INVALID_STREAM; - } - break; - - case GST_STREAM_ERROR_CODEC_NOT_FOUND: - case GST_STREAM_ERROR_TYPE_NOT_FOUND: - case GST_STREAM_ERROR_WRONG_TYPE: - return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT; - - case GST_STREAM_ERROR_FAILED: - { - /* Decoder Custom Message */ - if ( strstr(error->message, "ongoing") ) - { - if ( strncasecmp(klass, "audio", 5) ) - { - if ( ( player->can_support_codec & FOUND_PLUGIN_VIDEO ) ) - { - debug_log("Video can keep playing.\n"); - return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND; - } - else - { - goto CODEC_NOT_FOUND; - } - - } - else if ( strncasecmp(klass, "video", 5) ) - { - if ( ( player->can_support_codec & FOUND_PLUGIN_AUDIO ) ) - { - debug_log("Audio can keep playing.\n"); - return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND; - } - else - { - goto CODEC_NOT_FOUND; - } - } - } - return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT; - } - break; - - case GST_STREAM_ERROR_DECRYPT: - case GST_STREAM_ERROR_DECRYPT_NOKEY: - { - debug_error("decryption error, [%s] failed, reason : [%s]\n", src_element_name, error->message); - - if ( strstr(error->message, "rights expired") ) - { - return MM_ERROR_PLAYER_DRM_EXPIRED; - } - else if ( strstr(error->message, "no rights") ) - { - return MM_ERROR_PLAYER_DRM_NO_LICENSE; - } - else if ( strstr(error->message, "has future rights") ) - { - return MM_ERROR_PLAYER_DRM_FUTURE_USE; - } - else if ( strstr(error->message, "opl violation") ) - { - return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION; - } - return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED; - } - break; - - default: - break; - } - - MMPLAYER_FLEAVE(); - - return MM_ERROR_PLAYER_INVALID_STREAM; - -INTERNAL_ERROR: - return MM_ERROR_PLAYER_INTERNAL; - -CODEC_NOT_FOUND: - debug_log("not found any available codec. Player should be destroyed.\n"); - return MM_ERROR_PLAYER_CODEC_NOT_FOUND; -} - -static void -__mmplayer_handle_eos_delay( mm_player_t* player, int delay_in_ms ) -{ - return_if_fail( player ); - - - /* post now if delay is zero */ - if ( delay_in_ms == 0 || player->set_mode.pcm_extraction) - { - debug_log("eos delay is zero. posting EOS now\n"); - MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL ); - - if ( player->set_mode.pcm_extraction ) - __mmplayer_cancel_eos_timer(player); - - return; - } - - /* cancel if existing */ - __mmplayer_cancel_eos_timer( player ); - - /* init new timeout */ - /* NOTE : consider give high priority to this timer */ - debug_log("posting EOS message after [%d] msec\n", delay_in_ms); - - player->eos_timer = g_timeout_add( delay_in_ms, - __mmplayer_eos_timer_cb, player ); - - player->context.global_default = g_main_context_default (); - debug_log("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer); - - /* check timer is valid. if not, send EOS now */ - if ( player->eos_timer == 0 ) - { - debug_warning("creating timer for delayed EOS has failed. sending EOS now\n"); - MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL ); - } -} - -static void -__mmplayer_cancel_eos_timer( mm_player_t* player ) -{ - return_if_fail( player ); - - if ( player->eos_timer ) - { - debug_log("cancel eos timer"); - __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer); - player->eos_timer = 0; - } - - return; -} - -static gboolean -__mmplayer_eos_timer_cb(gpointer u_data) -{ - mm_player_t* player = NULL; - player = (mm_player_t*) u_data; - - return_val_if_fail( player, FALSE ); - - if ( player->play_count > 1 ) - { - gint ret_value = 0; - ret_value = __gst_set_position( player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE); - if (ret_value == MM_ERROR_NONE) - { - MMHandleType attrs = 0; - attrs = MMPLAYER_GET_ATTRS(player); - - /* we successeded to rewind. update play count and then wait for next EOS */ - player->play_count--; - - mm_attrs_set_int_by_name(attrs, "profile_play_count", player->play_count); - mmf_attrs_commit ( attrs ); - } - else - { - debug_error("seeking to 0 failed in repeat play"); - } - } - else - { - /* posting eos */ - MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL ); - } - - /* we are returning FALSE as we need only one posting */ - return FALSE; -} - -static gboolean -__mmplayer_link_decoder( mm_player_t* player, GstPad *srcpad) -{ - const gchar* name = NULL; - GstStructure* str = NULL; - GstCaps* srccaps = NULL; - - MMPLAYER_FENTER(); - - return_val_if_fail( player, FALSE ); - return_val_if_fail ( srcpad, FALSE ); - - /* to check any of the decoder (video/audio) need to be linked to parser*/ - srccaps = gst_pad_query_caps( srcpad, NULL); - if ( !srccaps ) - goto ERROR; - - str = gst_caps_get_structure( srccaps, 0 ); - if ( ! str ) - goto ERROR; - - name = gst_structure_get_name(str); - if ( ! name ) - goto ERROR; - - if (strstr(name, "video")) - { - if(player->videodec_linked) - { - debug_msg("Video decoder already linked\n"); - return FALSE; - } - } - if (strstr(name, "audio")) - { - if(player->audiodec_linked) - { - debug_msg("Audio decoder already linked\n"); - return FALSE; - } - } - - gst_caps_unref( srccaps ); - - MMPLAYER_FLEAVE(); - - return TRUE; - -ERROR: - if ( srccaps ) - gst_caps_unref( srccaps ); - - return FALSE; -} - -static gboolean -__mmplayer_link_sink( mm_player_t* player , GstPad *srcpad) -{ - const gchar* name = NULL; - GstStructure* str = NULL; - GstCaps* srccaps = NULL; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, FALSE ); - return_val_if_fail ( srcpad, FALSE ); - - /* to check any of the decoder (video/audio) need to be linked to parser*/ - srccaps = gst_pad_query_caps( srcpad, NULL ); - if ( !srccaps ) - goto ERROR; - - str = gst_caps_get_structure( srccaps, 0 ); - if ( ! str ) - goto ERROR; - - name = gst_structure_get_name(str); - if ( ! name ) - goto ERROR; - - if (strstr(name, "video")) - { - if(player->videosink_linked) - { - debug_msg("Video Sink already linked\n"); - return FALSE; - } - } - if (strstr(name, "audio")) - { - if(player->audiosink_linked) - { - debug_msg("Audio Sink already linked\n"); - return FALSE; - } - } - if (strstr(name, "text")) - { - if(player->textsink_linked) - { - debug_msg("Text Sink already linked\n"); - return FALSE; - } - } - - gst_caps_unref( srccaps ); - - MMPLAYER_FLEAVE(); - - return TRUE; - //return (!player->videosink_linked || !player->audiosink_linked); - -ERROR: - if ( srccaps ) - gst_caps_unref( srccaps ); - - return FALSE; -} - - -/* sending event to one of sinkelements */ -static gboolean -__gst_send_event_to_sink( mm_player_t* player, GstEvent* event ) -{ - GstEvent * event2 = NULL; - GList *sinks = NULL; - gboolean res = FALSE; - MMPLAYER_FENTER(); - - return_val_if_fail( player, FALSE ); - return_val_if_fail ( event, FALSE ); - - if ( player->play_subtitle && !player->use_textoverlay) - event2 = gst_event_copy((const GstEvent *)event); - - sinks = player->sink_elements; - while (sinks) - { - GstElement *sink = GST_ELEMENT_CAST (sinks->data); - - if (GST_IS_ELEMENT(sink)) - { - /* keep ref to the event */ - gst_event_ref (event); - - if ( (res = gst_element_send_event (sink, event)) ) - { - debug_log("sending event[%s] to sink element [%s] success!\n", - GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink) ); - - /* rtsp case, asyn_done is not called after seek during pause state */ - if (MMPLAYER_IS_RTSP_STREAMING(player)) - { - if (strstr(GST_EVENT_TYPE_NAME(event), "seek")) - { - if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) - { - debug_log("RTSP seek completed, after pause state..\n"); - player->doing_seek = FALSE; - MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL ); - } - - } - } - - if( MMPLAYER_IS_ES_BUFF_SRC(player)) - { - sinks = g_list_next (sinks); - continue; - } - else - break; - } - - debug_log("sending event[%s] to sink element [%s] failed. try with next one.\n", - GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink) ); - } - - sinks = g_list_next (sinks); - } - -#if 0 - if (internal_sub) - request pad name = sink0; - else - request pad name = sink1; // external -#endif - - /* Note : Textbin is not linked to the video or audio bin. - * It needs to send the event to the text sink seperatelly. - */ - if ( player->play_subtitle && !player->use_textoverlay) - { - GstElement *text_sink = GST_ELEMENT_CAST (player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst); - - if (GST_IS_ELEMENT(text_sink)) - { - /* keep ref to the event */ - gst_event_ref (event2); - - if ((res = gst_element_send_event (text_sink, event2))) - { - debug_log("sending event[%s] to subtitle sink element [%s] success!\n", - GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink) ); - } - else - { - debug_error("sending event[%s] to subtitle sink element [%s] failed!\n", - GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink) ); - } - - gst_event_unref (event2); - } - } - - gst_event_unref (event); - - MMPLAYER_FLEAVE(); - - return res; -} - -static void -__mmplayer_add_sink( mm_player_t* player, GstElement* sink ) -{ - MMPLAYER_FENTER(); - - return_if_fail ( player ); - return_if_fail ( sink ); - - player->sink_elements = - g_list_append(player->sink_elements, sink); - - MMPLAYER_FLEAVE(); -} - -static void -__mmplayer_del_sink( mm_player_t* player, GstElement* sink ) -{ - MMPLAYER_FENTER(); - - return_if_fail ( player ); - return_if_fail ( sink ); - - player->sink_elements = - g_list_remove(player->sink_elements, sink); - - MMPLAYER_FLEAVE(); -} - -static gboolean -__gst_seek(mm_player_t* player, GstElement * element, gdouble rate, - GstFormat format, GstSeekFlags flags, GstSeekType cur_type, - gint64 cur, GstSeekType stop_type, gint64 stop ) -{ - GstEvent* event = NULL; - gboolean result = FALSE; - - MMPLAYER_FENTER(); - - return_val_if_fail( player, FALSE ); - - __mmplayer_drop_subtitle(player, FALSE); - - event = gst_event_new_seek (rate, format, flags, cur_type, - cur, stop_type, stop); - - result = __gst_send_event_to_sink( player, event ); - - MMPLAYER_FLEAVE(); - - return result; -} - -/* NOTE : be careful with calling this api. please refer to below glib comment - * glib comment : Note that there is a bug in GObject that makes this function much - * less useful than it might seem otherwise. Once gobject is disposed, the callback - * will no longer be called, but, the signal handler is not currently disconnected. - * If the instance is itself being freed at the same time than this doesn't matter, - * since the signal will automatically be removed, but if instance persists, - * then the signal handler will leak. You should not remove the signal yourself - * because in a future versions of GObject, the handler will automatically be - * disconnected. - * - * It's possible to work around this problem in a way that will continue to work - * with future versions of GObject by checking that the signal handler is still - * connected before disconnected it: - * - * if (g_signal_handler_is_connected (instance, id)) - * g_signal_handler_disconnect (instance, id); - */ -static void -__mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type) -{ - GList* sig_list = NULL; - MMPlayerSignalItem* item = NULL; - - MMPLAYER_FENTER(); - - return_if_fail( player ); - - debug_log("release signals type : %d", type); - - if ((type < MM_PLAYER_SIGNAL_TYPE_AUTOPLUG) || (type >= MM_PLAYER_SIGNAL_TYPE_ALL)) - { - __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG); - __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN); - __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN); - __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN); - __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_OTHERS); - return; - } - - sig_list = player->signals[type]; - - for ( ; sig_list; sig_list = sig_list->next ) - { - item = sig_list->data; - - if ( item && item->obj && GST_IS_ELEMENT(item->obj) ) - { - if ( g_signal_handler_is_connected ( item->obj, item->sig ) ) - { - g_signal_handler_disconnect ( item->obj, item->sig ); - } - } - - MMPLAYER_FREEIF( item ); - } - - g_list_free ( player->signals[type] ); - player->signals[type] = NULL; - - MMPLAYER_FLEAVE(); - - return; -} - -int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay) -{ - mm_player_t* player = 0; - int prev_display_surface_type = 0; - void *prev_display_overlay = NULL; - const gchar *klass = NULL; - gchar *cur_videosink_name = NULL; - int ret = 0; - int i = 0; - int num_of_dec = 2; /* DEC1, DEC2 */ - - MMPLAYER_FENTER(); - - return_val_if_fail(handle, MM_ERROR_COMMON_INVALID_ARGUMENT); - return_val_if_fail(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT); - - player = MM_PLAYER_CAST(handle); - - if (surface_type < MM_DISPLAY_SURFACE_X && surface_type >= MM_DISPLAY_SURFACE_NUM) - { - debug_error("Not support this surface type(%d) for changing vidoesink", surface_type); - MMPLAYER_FLEAVE(); - return MM_ERROR_INVALID_ARGUMENT; - } - - /* load previous attributes */ - if (player->attrs) - { - mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &prev_display_surface_type); - mm_attrs_get_data_by_name (player->attrs, "display_overlay", &prev_display_overlay); - debug_log("[0: X surface, 1: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type); - if (prev_display_surface_type == surface_type) - { - debug_log("incoming display surface type is same as previous one, do nothing.."); - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; - } - } - else - { - debug_error("failed to load attributes"); - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_INTERNAL; - } - - /* check videosink element is created */ - if (!player->pipeline || !player->pipeline->videobin || - !player->pipeline->videobin[MMPLAYER_V_SINK].gst ) - { - debug_log("videosink element is not yet ready"); - - /* videobin is not created yet, so we just set attributes related to display surface */ - debug_log("store display attribute for given surface type(%d)", surface_type); - mm_attrs_set_int_by_name (player->attrs, "display_surface_type", surface_type); - mm_attrs_set_data_by_name (player->attrs, "display_overlay", display_overlay, sizeof(display_overlay)); - if ( mmf_attrs_commit ( player->attrs ) ) - { - debug_error("failed to commit attribute"); - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_INTERNAL; - } - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; - } - else - { - /* get player command status */ - if ( !(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE) ) - { - debug_error("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command",player->cmd); - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_INVALID_STATE; - } - - /* get a current videosink name */ - cur_videosink_name = GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_SINK].gst); - - /* surface change */ - for ( i = 0 ; i < num_of_dec ; i++) - { - if ( player->pipeline->mainbin && - player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst ) - { - GstElementFactory *decfactory; - decfactory = gst_element_get_factory (player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst); - - klass = gst_element_factory_get_metadata (decfactory, GST_ELEMENT_METADATA_KLASS); - if ((g_strrstr(klass, "Codec/Decoder/Video"))) - { - if ( !strncmp(cur_videosink_name, "x", 1) && (surface_type == MM_DISPLAY_SURFACE_EVAS) ) - { - ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_evas, surface_type, display_overlay); - if (ret) - { - goto ERROR_CASE; - } - else - { - debug_warning("success to changing display surface(%d)",surface_type); - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; - } - } - else if (!strncmp(cur_videosink_name, "evas", 4) && (surface_type == MM_DISPLAY_SURFACE_X) ) - { - ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_x, surface_type, display_overlay); - if (ret) - { - goto ERROR_CASE; - } - else - { - debug_warning("success to changing display surface(%d)",surface_type); - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; - } - } - else - { - debug_error("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface",surface_type, cur_videosink_name); - ret = MM_ERROR_PLAYER_INTERNAL; - goto ERROR_CASE; - } - } - } - } - } - -ERROR_CASE: - /* rollback to previous attributes */ - mm_attrs_set_int_by_name (player->attrs, "display_surface_type", prev_display_surface_type); - mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*)); - if ( mmf_attrs_commit ( player->attrs ) ) - { - debug_error("failed to commit attributes to rollback"); - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_INTERNAL; - } - MMPLAYER_FLEAVE(); - return ret; -} - -/* NOTE : It does not support some use cases, eg using colorspace converter */ -int -__mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay) -{ - GstPad *src_pad_dec = NULL; - GstPad *sink_pad_videosink = NULL; - GstPad *sink_pad_videobin = NULL; - GstClock *clock = NULL; - MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM; - int ret = MM_ERROR_NONE; - gboolean is_audiobin_created = TRUE; - - MMPLAYER_FENTER(); - - return_val_if_fail(player, MM_ERROR_COMMON_INVALID_ARGUMENT); - return_val_if_fail(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT); - return_val_if_fail(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT); - - debug_log("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element); - debug_log("surface type(%d), display overlay(%x)", surface_type, display_overlay); - - /* get information whether if audiobin is created */ - if ( !player->pipeline->audiobin || - !player->pipeline->audiobin[MMPLAYER_A_SINK].gst ) - { - debug_warning("audiobin is null, this video content may not have audio data"); - is_audiobin_created = FALSE; - } - - /* get current state of player */ - previous_state = MMPLAYER_CURRENT_STATE(player); - debug_log("previous state(%d)", previous_state); - - - /* get src pad of decoder and block it */ - src_pad_dec = gst_element_get_static_pad (GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src"); - if (!src_pad_dec) - { - debug_error("failed to get src pad from decode in mainbin"); - return MM_ERROR_PLAYER_INTERNAL; - } - - if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) - { - debug_warning("trying to block pad(video)"); -// if (!gst_pad_set_blocked (src_pad_dec, TRUE)) - gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, - NULL, NULL, NULL); - - { - debug_error("failed to set block pad(video)"); - return MM_ERROR_PLAYER_INTERNAL; - } - debug_warning("pad is blocked(video)"); - } - else - { - /* no data flows, so no need to do pad_block */ - if (player->doing_seek) { - debug_warning("not completed seek(%d), do nothing", player->doing_seek); - } - debug_log("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)"); - } - - /* remove pad */ - if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, - GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) - { - debug_error("failed to remove previous ghost_pad for videobin"); - return MM_ERROR_PLAYER_INTERNAL; - } - - /* change state of videobin to NULL */ - debug_log("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL); - ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL); - if (ret != GST_STATE_CHANGE_SUCCESS) - { - debug_error("failed to change state of videobin to NULL"); - return MM_ERROR_PLAYER_INTERNAL; - } - - /* unlink between decoder and videobin and remove previous videosink from videobin */ - GST_ELEMENT_UNLINK(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst),GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst)); - if ( !gst_bin_remove (GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst)) ) - { - debug_error("failed to remove former videosink from videobin"); - return MM_ERROR_PLAYER_INTERNAL; - } - - __mmplayer_del_sink( player, player->pipeline->videobin[MMPLAYER_V_SINK].gst ); - - /* create a new videosink and add it to videobin */ - player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, videosink_element); - gst_bin_add (GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst)); - __mmplayer_add_sink( player, player->pipeline->videobin[MMPLAYER_V_SINK].gst ); - g_object_set (G_OBJECT (player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL); - - /* save attributes */ - if (player->attrs) - { - /* set a new display surface type */ - mm_attrs_set_int_by_name (player->attrs, "display_surface_type", surface_type); - /* set a new diplay overlay */ - switch (surface_type) - { - case MM_DISPLAY_SURFACE_X: - debug_log("save attributes related to display surface to X : xid = %d", *(int*)display_overlay); - mm_attrs_set_data_by_name (player->attrs, "display_overlay", display_overlay, sizeof(display_overlay)); - break; - case MM_DISPLAY_SURFACE_EVAS: - debug_log("save attributes related to display surface to EVAS : evas image object = %x", display_overlay); - mm_attrs_set_data_by_name (player->attrs, "display_overlay", display_overlay, sizeof(void*)); - break; - default: - debug_error("invalid type(%d) for changing display surface",surface_type); - MMPLAYER_FLEAVE(); - return MM_ERROR_INVALID_ARGUMENT; - } - if ( mmf_attrs_commit ( player->attrs ) ) - { - debug_error("failed to commit"); - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_INTERNAL; - } - } - else - { - debug_error("player->attrs is null, failed to save attributes"); - MMPLAYER_FLEAVE(); - return MM_ERROR_PLAYER_INTERNAL; - } - - /* update video param */ - if ( MM_ERROR_NONE != _mmplayer_update_video_param( player ) ) - { - debug_error("failed to update video param"); - return MM_ERROR_PLAYER_INTERNAL; - } - - /* change state of videobin to READY */ - debug_log("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY); - ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY); - if (ret != GST_STATE_CHANGE_SUCCESS) - { - debug_error("failed to change state of videobin to READY"); - return MM_ERROR_PLAYER_INTERNAL; - } - - /* change ghostpad */ - sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink"); - if ( !sink_pad_videosink ) - { - debug_error("failed to get sink pad from videosink element"); - return MM_ERROR_PLAYER_INTERNAL; - } - player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink); - if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) - { - debug_error("failed to set active to ghost_pad"); - return MM_ERROR_PLAYER_INTERNAL; - } - if ( FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin) ) - { - debug_error("failed to change ghostpad for videobin"); - return MM_ERROR_PLAYER_INTERNAL; - } - gst_object_unref(sink_pad_videosink); - - /* link decoder with videobin */ - sink_pad_videobin = gst_element_get_static_pad( GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink"); - if ( !sink_pad_videobin ) - { - debug_error("failed to get sink pad from videobin"); - return MM_ERROR_PLAYER_INTERNAL; - } - if ( GST_PAD_LINK_OK != GST_PAD_LINK(src_pad_dec, sink_pad_videobin) ) - { - debug_error("failed to link"); - return MM_ERROR_PLAYER_INTERNAL; - } - gst_object_unref(sink_pad_videobin); - - /* clock setting for a new videosink plugin */ - /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink, - so we set it from audiosink plugin or pipeline(system clock) */ - if (!is_audiobin_created) - { - debug_warning("audiobin is not created, get clock from pipeline.."); - clock = GST_ELEMENT_CLOCK (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst); - } - else - { - clock = GST_ELEMENT_CLOCK (player->pipeline->audiobin[MMPLAYER_A_SINK].gst); - } - if (clock) - { - GstClockTime now; - GstClockTime base_time; - debug_log("set the clock to videosink"); - gst_element_set_clock (GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock); - clock = GST_ELEMENT_CLOCK (player->pipeline->videobin[MMPLAYER_V_SINK].gst); - if (clock) - { - debug_log("got clock of videosink"); - now = gst_clock_get_time ( clock ); - base_time = GST_ELEMENT_CAST (player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time; - debug_log ("at time %" GST_TIME_FORMAT ", base %" - GST_TIME_FORMAT, GST_TIME_ARGS (now), GST_TIME_ARGS (base_time)); - } - else - { - debug_error("failed to get clock of videosink after setting clock"); - return MM_ERROR_PLAYER_INTERNAL; - } - } - else - { - debug_warning("failed to get clock, maybe it is the time before first playing"); - } - - if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) - { - /* change state of videobin to PAUSED */ - debug_log("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING); - ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING); - if (ret != GST_STATE_CHANGE_FAILURE) - { - debug_warning("change state of videobin to PLAYING, ret(%d)", ret); - } - else - { - debug_error("failed to change state of videobin to PLAYING"); - return MM_ERROR_PLAYER_INTERNAL; - } - - /* release blocked and unref src pad of video decoder */ - #if 0 - if (!gst_pad_set_blocked (src_pad_dec, FALSE)) - { - debug_error("failed to set pad blocked FALSE(video)"); - return MM_ERROR_PLAYER_INTERNAL; - } - #endif - debug_warning("pad is unblocked(video)"); - } - else - { - if (player->doing_seek) { - debug_warning("not completed seek(%d)", player->doing_seek); - } - /* change state of videobin to PAUSED */ - debug_log("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED); - ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED); - if (ret != GST_STATE_CHANGE_FAILURE) - { - debug_warning("change state of videobin to PAUSED, ret(%d)", ret); - } - else - { - debug_error("failed to change state of videobin to PLAYING"); - return MM_ERROR_PLAYER_INTERNAL; - } - - /* already skipped pad block */ - debug_log("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)"); - } - - /* do get/set position for new videosink plugin */ - { - unsigned long position = 0; - gint64 pos_msec = 0; - - debug_log("do get/set position for new videosink plugin"); - if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position )) - { - debug_error("failed to get position"); - return MM_ERROR_PLAYER_INTERNAL; - } -#ifdef SINKCHANGE_WITH_ACCURATE_SEEK - /* accurate seek */ - if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE )) - { - debug_error("failed to set position"); - return MM_ERROR_PLAYER_INTERNAL; - } -#else - /* key unit seek */ - pos_msec = position * G_GINT64_CONSTANT(1000000); - ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0, - GST_FORMAT_TIME, ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT ), - GST_SEEK_TYPE_SET, pos_msec, - GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE ); - if ( !ret ) - { - debug_error("failed to set position"); - return MM_ERROR_PLAYER_INTERNAL; - } -#endif - } - - if (src_pad_dec) - { - gst_object_unref (src_pad_dec); - } - debug_log("success to change sink"); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - - -/* Note : if silent is true, then subtitle would not be displayed. :*/ -int _mmplayer_set_subtitle_silent (MMHandleType hplayer, int silent) -{ - mm_player_t* player = (mm_player_t*) hplayer; - - MMPLAYER_FENTER(); - - /* check player handle */ - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - player->set_mode.subtitle_off = silent; - - debug_log("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF"); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -int _mmplayer_remove_audio_parser_decoder(mm_player_t* player,GstPad *inpad) -{ - int result = MM_ERROR_NONE; - GstPad *peer = NULL,*pad = NULL; - GstElement *Element = NULL; - MMPlayerGstElement* mainbin = NULL; - mainbin = player->pipeline->mainbin; - - #if 0 - if(!gst_pad_set_blocked(inpad,TRUE)) - { - result = MM_ERROR_PLAYER_INTERNAL; - goto EXIT; - } - #endif - gst_pad_add_probe(inpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, - NULL, NULL, NULL); - - /*Getting pad connected to demuxer audio pad */ - peer = gst_pad_get_peer(inpad); - /* Disconnecting Demuxer and its peer plugin [audio] */ - if(peer) - { - if(!gst_pad_unlink(inpad,peer)) - { - result = MM_ERROR_PLAYER_INTERNAL; - goto EXIT; - } - } - else - { - result = MM_ERROR_PLAYER_INTERNAL; - goto EXIT; - } - /*Removing elements between Demuxer and audiobin*/ - while(peer != NULL) - { - gchar *Element_name = NULL; - gchar *factory_name = NULL; - GList *elements = NULL; - GstElementFactory *factory = NULL; - /*Getting peer element*/ - Element = gst_pad_get_parent_element(peer); - if(Element == NULL) - { - gst_object_unref(peer); - result = MM_ERROR_PLAYER_INTERNAL; - break; - } - - Element_name = gst_element_get_name(Element); - factory = gst_element_get_factory(Element); - /*checking the element is audio bin*/ - if(!strcmp(Element_name,"audiobin")) - { - gst_object_unref(peer); - result = MM_ERROR_NONE; - g_free(Element_name); - break; - } - factory_name = GST_OBJECT_NAME(factory); - pad = gst_element_get_static_pad(Element,"src"); - if(pad == NULL) - { - result = MM_ERROR_PLAYER_INTERNAL; - g_free(Element_name); - break; - } - gst_object_unref(peer); - peer = gst_pad_get_peer(pad); - if(peer) - { - if(!gst_pad_unlink(pad,peer)) - { - gst_object_unref(peer); - gst_object_unref(pad); - result = MM_ERROR_PLAYER_INTERNAL; - g_free(Element_name); - break; - } - } - elements = player->parsers; - /* Removing the element form the list*/ - for ( ; elements; elements = g_list_next(elements)) - { - Element_name = elements->data; - if(g_strrstr(Element_name,factory_name)) - { - player->parsers = g_list_remove(player->parsers,elements->data); - } - } - gst_element_set_state(Element,GST_STATE_NULL); - gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),Element); - gst_object_unref(pad); - if(Element == mainbin[MMPLAYER_M_Q1].gst) - { - mainbin[MMPLAYER_M_Q1].gst = NULL; - } - else if(Element == mainbin[MMPLAYER_M_Q2].gst) - { - mainbin[MMPLAYER_M_Q2].gst = NULL; - } - else if(Element == mainbin[MMPLAYER_M_DEC1].gst) - { - mainbin[MMPLAYER_M_DEC1].gst = NULL; - } - else if(Element == mainbin[MMPLAYER_M_DEC2].gst) - { - mainbin[MMPLAYER_M_DEC2].gst = NULL; - } - gst_object_unref(Element); - } -EXIT: - return result; -} - -int _mmplayer_sync_subtitle_pipeline(mm_player_t* player) -{ - MMPlayerGstElement* mainbin = NULL; - MMPlayerGstElement* textbin = NULL; - GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE; - GstState current_state = GST_STATE_VOID_PENDING; - GstState element_state = GST_STATE_VOID_PENDING; - GstState element_pending_state = GST_STATE_VOID_PENDING; - gint64 time = 0; - GstEvent *event = NULL; - int result = MM_ERROR_NONE; - - GstClock *curr_clock = NULL; - GstClockTime base_time, start_time, curr_time; - - - MMPLAYER_FENTER(); - - /* check player handle */ - return_val_if_fail ( player && player->pipeline , MM_ERROR_PLAYER_NOT_INITIALIZED); - - if (!(player->pipeline->mainbin) || !(player->pipeline->textbin)) - { - debug_error("Pipeline is not in proper state\n"); - result = MM_ERROR_PLAYER_NOT_INITIALIZED; - goto EXIT; - } - - mainbin = player->pipeline->mainbin; - textbin = player->pipeline->textbin; - - current_state = GST_STATE (mainbin[MMPLAYER_M_PIPE].gst); - - // sync clock with current pipeline - curr_clock = GST_ELEMENT_CLOCK (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst); - curr_time = gst_clock_get_time (curr_clock); - - base_time = gst_element_get_base_time (GST_ELEMENT_CAST (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)); - start_time = gst_element_get_start_time (GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)); - - debug_log ("base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT, - GST_TIME_ARGS (base_time), GST_TIME_ARGS (start_time), GST_TIME_ARGS (curr_time)); - - if (current_state > GST_STATE_READY) - { - // sync state with current pipeline - gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED); - gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED); - gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED); - - ret = gst_element_get_state (mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND); - if ( GST_STATE_CHANGE_FAILURE == ret ) - { - debug_error("fail to state change.\n"); - } - } - - gst_element_set_base_time (textbin[MMPLAYER_T_BIN].gst, base_time); - gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time); - - if (curr_clock) - { - gst_element_set_clock (textbin[MMPLAYER_T_BIN].gst, curr_clock); - gst_object_unref (curr_clock); - } - - // seek to current position - if (!gst_element_query_position (mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) - { - result = MM_ERROR_PLAYER_INVALID_STATE; - debug_error("gst_element_query_position failed, invalid state\n"); - goto EXIT; - } - - debug_log("seek time = %lld\n", time); - event = gst_event_new_seek (1.0, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1); - if (event) - { - __gst_send_event_to_sink(player, event); - } - else - { - result = MM_ERROR_PLAYER_INTERNAL; - debug_error("gst_event_new_seek failed\n"); - goto EXIT; - } - - // sync state with current pipeline - gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst); - gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst); - gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst); - -EXIT: - return result; -} - -static int -__mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE; - GstState current_state = GST_STATE_VOID_PENDING; - - MMHandleType attrs = 0; - MMPlayerGstElement* mainbin = NULL; - MMPlayerGstElement* textbin = NULL; - - gchar* subtitle_uri = NULL; - int result = MM_ERROR_NONE; - const gchar *charset = NULL; - - MMPLAYER_FENTER(); - - /* check player handle */ - return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - return_val_if_fail( filepath, MM_ERROR_COMMON_INVALID_ARGUMENT ); - - if (!(player->pipeline) || !(player->pipeline->mainbin)) - { - result = MM_ERROR_PLAYER_INVALID_STATE; - debug_error("Pipeline is not in proper state\n"); - goto EXIT; - } - - mainbin = player->pipeline->mainbin; - textbin = player->pipeline->textbin; - - current_state = GST_STATE (mainbin[MMPLAYER_M_PIPE].gst); - if (current_state < GST_STATE_READY) - { - result = MM_ERROR_PLAYER_INVALID_STATE; - debug_error("Pipeline is not in proper state\n"); - goto EXIT; - } - - attrs = MMPLAYER_GET_ATTRS(player); - if (!attrs) - { - debug_error("cannot get content attribute\n"); - result = MM_ERROR_PLAYER_INTERNAL; - goto EXIT; - } - - mm_attrs_get_string_by_name (attrs, "subtitle_uri", &subtitle_uri); - if (!subtitle_uri || strlen(subtitle_uri) < 1) - { - debug_error("subtitle uri is not proper filepath\n"); - result = MM_ERROR_PLAYER_INVALID_URI; - goto EXIT; - } - - debug_log("old subtitle file path is [%s]\n", subtitle_uri); - debug_log("new subtitle file path is [%s]\n", filepath); - - if (!strcmp (filepath, subtitle_uri)) - { - debug_log("No need to swtich subtitle, as input filepath is same as current filepath\n"); - goto EXIT; - } - else - { - mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath); - if (mmf_attrs_commit(player->attrs)) - { - debug_error("failed to commit.\n"); - goto EXIT; - } - } - - //gst_pad_set_blocked_async(src-srcpad, TRUE) - - ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY); - if (ret != GST_STATE_CHANGE_SUCCESS) - { - debug_error("failed to change state of textbin to READY"); - result = MM_ERROR_PLAYER_INTERNAL; - goto EXIT; - } - - ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY); - if (ret != GST_STATE_CHANGE_SUCCESS) - { - debug_error("failed to change state of subparse to READY"); - result = MM_ERROR_PLAYER_INTERNAL; - goto EXIT; - } - - ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY); - if (ret != GST_STATE_CHANGE_SUCCESS) - { - debug_error("failed to change state of filesrc to READY"); - result = MM_ERROR_PLAYER_INTERNAL; - goto EXIT; - } - - g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL); - - charset = util_get_charset(filepath); - if (charset) - { - debug_log ("detected charset is %s\n", charset ); - g_object_set (G_OBJECT (mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL); - } - - result = _mmplayer_sync_subtitle_pipeline(player); - -EXIT: - MMPLAYER_FLEAVE(); - return result; -} - -/* API to switch between external subtitles */ -int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath) -{ - int result = MM_ERROR_NONE; - mm_player_t* player = (mm_player_t*)hplayer; - - MMPLAYER_FENTER(); - - /* check player handle */ - return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - if (!player->pipeline) // IDLE state - { - mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath); - if (mmf_attrs_commit(player->attrs)) - { - debug_error("failed to commit.\n"); - result= MM_ERROR_PLAYER_INTERNAL; - } - } - else // curr state <> IDLE (READY, PAUSE, PLAYING..) - { - if ( filepath == NULL ) - return MM_ERROR_COMMON_INVALID_ARGUMENT; - - if (!__mmplayer_check_subtitle(player)) - { - mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath); - if (mmf_attrs_commit(player->attrs)) - { - debug_error("failed to commit.\n"); - result = MM_ERROR_PLAYER_INTERNAL; - } - - if ( MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player) ) - debug_error("fail to create subtitle src\n"); - - result = _mmplayer_sync_subtitle_pipeline(player); - } - else - { - result = __mmplayer_change_external_subtitle_language(player, filepath); - } - } - - MMPLAYER_FLEAVE(); - return result; -} - -static int -__mmplayer_change_selector_pad (mm_player_t* player, MMPlayerTrackType type, int index) -{ - int result = MM_ERROR_NONE; - gchar* change_pad_name = NULL; - GstPad* sinkpad = NULL; - MMPlayerGstElement* mainbin = NULL; - enum MainElementID elemId = MMPLAYER_M_NUM; - GstCaps* caps = NULL; - gint total_track_num = 0; - - MMPLAYER_FENTER(); - - return_val_if_fail (player && player->pipeline && player->pipeline->mainbin, - MM_ERROR_PLAYER_NOT_INITIALIZED); - - debug_log ("Change Track(%d) to %d\n", type, index); - - mainbin = player->pipeline->mainbin; - - if (type == MM_PLAYER_TRACK_TYPE_AUDIO) - { - elemId = MMPLAYER_M_A_INPUT_SELECTOR; - } - else if (type == MM_PLAYER_TRACK_TYPE_TEXT) - { - elemId = MMPLAYER_M_T_INPUT_SELECTOR; - } - else - { - debug_error ("Track Type Error\n"); - goto EXIT; - } - - if (mainbin[elemId].gst == NULL) - { - result = MM_ERROR_PLAYER_NO_OP; - debug_log ("Req track doesn't exist\n"); - goto EXIT; - } - - total_track_num = player->selector[type].total_track_num; - if (total_track_num <= 0) - { - result = MM_ERROR_PLAYER_NO_OP; - debug_log ("Language list is not available \n"); - goto EXIT; - } - - if ((index < 0) || (index >= total_track_num)) - { - result = MM_ERROR_INVALID_ARGUMENT; - debug_log ("Not a proper index : %d \n", index); - goto EXIT; - } - - /*To get the new pad from the selector*/ - change_pad_name = g_strdup_printf ("sink_%u", index); - if (change_pad_name == NULL) - { - result = MM_ERROR_PLAYER_INTERNAL; - debug_log ("Pad does not exists\n"); - goto EXIT; - } - - debug_log ("new active pad name: %s\n", change_pad_name); - - sinkpad = gst_element_get_static_pad (mainbin[elemId].gst, change_pad_name); - if (sinkpad == NULL) - { - debug_log ("sinkpad is NULL"); - result = MM_ERROR_PLAYER_INTERNAL; - goto EXIT; - } - - debug_log ("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad)); - g_object_set (mainbin[elemId].gst, "active-pad", sinkpad, NULL); - - caps = gst_pad_get_current_caps(sinkpad); - MMPLAYER_LOG_GST_CAPS_TYPE(caps); - - if (sinkpad) - gst_object_unref (sinkpad); - - if (type == MM_PLAYER_TRACK_TYPE_AUDIO) - { - __mmplayer_set_audio_attrs (player, caps); - } - -EXIT: - - MMPLAYER_FREEIF(change_pad_name); - return result; -} - -int _mmplayer_change_track_language (MMHandleType hplayer, MMPlayerTrackType type, int index) -{ - int result = MM_ERROR_NONE; - mm_player_t* player = NULL; - MMPlayerGstElement* mainbin = NULL; - - gint current_active_index = 0; - - GstState current_state = GST_STATE_VOID_PENDING; - GstEvent* event = NULL; - gint64 time = 0; - - MMPLAYER_FENTER(); - - player = (mm_player_t*)hplayer; - return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - if (!player->pipeline) - { - debug_error ("Track %d pre setting -> %d\n", type, index); - - player->selector[type].active_pad_index = index; - goto EXIT; - } - - mainbin = player->pipeline->mainbin; - - current_active_index = player->selector[type].active_pad_index; - - /*If index is same as running index no need to change the pad*/ - if (current_active_index == index) - { - goto EXIT; - } - - if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) - { - result = MM_ERROR_PLAYER_INVALID_STATE; - goto EXIT; - } - - current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst); - if (current_state < GST_STATE_PAUSED) - { - result = MM_ERROR_PLAYER_INVALID_STATE; - debug_warning ("Pipeline not in porper state\n"); - goto EXIT; - } - - result = __mmplayer_change_selector_pad(player, type, index); - if (result != MM_ERROR_NONE) - { - debug_error ("change selector pad error\n"); - goto EXIT; - } - - player->selector[type].active_pad_index = index; - - if (current_state == GST_STATE_PLAYING) - { - event = gst_event_new_seek (1.0, GST_FORMAT_TIME,(GstSeekFlags) (GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1); - if (event) - { - __gst_send_event_to_sink (player, event); - } - else - { - result = MM_ERROR_PLAYER_INTERNAL; - goto EXIT; - } - } - -EXIT: - return result; -} - -int _mmplayer_get_subtitle_silent (MMHandleType hplayer, int* silent) -{ - mm_player_t* player = (mm_player_t*) hplayer; - - MMPLAYER_FENTER(); - - /* check player handle */ - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - *silent = player->set_mode.subtitle_off; - - debug_log("subtitle is %s.\n", silent ? "ON" : "OFF"); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -const gchar * -__get_state_name ( int state ) -{ - switch ( state ) - { - case MM_PLAYER_STATE_NULL: - return "NULL"; - case MM_PLAYER_STATE_READY: - return "READY"; - case MM_PLAYER_STATE_PAUSED: - return "PAUSED"; - case MM_PLAYER_STATE_PLAYING: - return "PLAYING"; - case MM_PLAYER_STATE_NONE: - return "NONE"; - default: - return "INVAID"; - } -} - -gboolean -__is_rtsp_streaming ( mm_player_t* player ) -{ - return_val_if_fail ( player, FALSE ); - - return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_RTSP ) ? TRUE : FALSE; -} - -gboolean -__is_wfd_streaming ( mm_player_t* player ) -{ - return_val_if_fail ( player, FALSE ); - - return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_WFD ) ? TRUE : FALSE; -} - -static gboolean -__is_http_streaming ( mm_player_t* player ) -{ - return_val_if_fail ( player, FALSE ); - - return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_HTTP ) ? TRUE : FALSE; -} - -static gboolean -__is_streaming ( mm_player_t* player ) -{ - return_val_if_fail ( player, FALSE ); - - return ( __is_http_progressive_down( player ) || __is_rtsp_streaming ( player ) || __is_wfd_streaming ( player ) || __is_http_streaming ( player ) - || __is_http_live_streaming ( player ) || __is_dash_streaming ( player ) || __is_smooth_streaming(player) ) ? TRUE : FALSE; -} - -gboolean -__is_live_streaming ( mm_player_t* player ) -{ - return_val_if_fail ( player, FALSE ); - - return ( __is_rtsp_streaming ( player ) && player->streaming_type == STREAMING_SERVICE_LIVE ) ? TRUE : FALSE; -} - -static gboolean -__is_http_live_streaming( mm_player_t* player ) -{ - return_val_if_fail( player, FALSE ); - - return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS ) ? TRUE : FALSE; -} - -static gboolean -__is_dash_streaming ( mm_player_t* player ) -{ - return_val_if_fail ( player, FALSE ); - - return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_DASH ) ? TRUE : FALSE; -} - -static gboolean -__is_smooth_streaming ( mm_player_t* player ) -{ - return_val_if_fail ( player, FALSE ); - - return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_SS ) ? TRUE : FALSE; -} - - -static gboolean -__is_http_progressive_down(mm_player_t* player) -{ - return_val_if_fail( player, FALSE ); - - return ((player->pd_mode) ? TRUE:FALSE); -} - -gboolean -__is_es_buff_src( mm_player_t* player ) -{ - return_val_if_fail ( player, FALSE ); - - return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_ES_BUFF) ? TRUE : FALSE; -} - -gboolean -__has_suffix(mm_player_t* player, const gchar* suffix) -{ - return_val_if_fail( player, FALSE ); - return_val_if_fail( suffix, FALSE ); - - gboolean ret = FALSE; - gchar* t_url = g_ascii_strdown(player->profile.uri, -1); - gchar* t_suffix = g_ascii_strdown(suffix, -1); - - if ( g_str_has_suffix(player->profile.uri, suffix) ) - { - ret = TRUE; - } - - MMPLAYER_FREEIF(t_url); - MMPLAYER_FREEIF(t_suffix); - - return ret; -} - -int -_mmplayer_set_display_zoom(MMHandleType hplayer, float level, int x, int y) -{ - mm_player_t* player = (mm_player_t*) hplayer; - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - MMPLAYER_VIDEO_SINK_CHECK(player); - - debug_log("setting display zoom level = %f, offset = %d, %d", level, x, y); - - g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", level, "zoom-pos-x", x, "zoom-pos-y", y, NULL); - - return MM_ERROR_NONE; -} -int -_mmplayer_get_display_zoom(MMHandleType hplayer, float *level, int *x, int *y) -{ - - mm_player_t* player = (mm_player_t*) hplayer; - float _level = 0.0; - int _x = 0; - int _y = 0; - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - MMPLAYER_VIDEO_SINK_CHECK(player); - - g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", &_level, "zoom-pos-x", &_x, "zoom-pos-y", &_y, NULL); - - debug_log("display zoom level = %f, start off x = %d, y = %d", _level, _x, _y); - - *level = _level; - *x = _x; - *y = _y; - - return MM_ERROR_NONE; -} - -int -_mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode) -{ - mm_player_t* player = (mm_player_t*) hplayer; - - return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) - { - MMPLAYER_PRINT_STATE(player); - debug_error("wrong-state : can't set the download mode to parse"); - return MM_ERROR_PLAYER_INVALID_STATE; - } - - debug_log("set video hub download mode to %s", (mode)?"ON":"OFF"); - player->video_hub_download_mode = mode; - - return MM_ERROR_NONE; -} - -int -_mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable) -{ - mm_player_t* player = (mm_player_t*) hplayer; - - return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - debug_log("enable sync handler : %s", (enable)?"ON":"OFF"); - player->sync_handler = enable; - - return MM_ERROR_NONE; -} - -int -_mmplayer_use_system_clock (MMHandleType hplayer) -{ - mm_player_t* player = (mm_player_t*) hplayer; - - return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - debug_log("change clock provider to system"); - - // to use system clock - player->ini.provide_clock_for_movie = FALSE; - player->ini.provide_clock_for_music = FALSE; - - return MM_ERROR_NONE; -} - -int -_mmplayer_set_video_share_master_clock( MMHandleType hplayer, - long long clock, - long long clock_delta, - long long video_time, - long long media_clock, - long long audio_time) -{ - mm_player_t* player = (mm_player_t*) hplayer; - MMPlayerGstElement* mainbin = NULL; - GstClockTime start_time_audio = 0, start_time_video = 0; - GstClockTimeDiff base_time = 0, new_base_time = 0; - MMPlayerStateType current_state = MM_PLAYER_STATE_NONE; - gint64 api_delta = 0; - gint64 position = 0, position_delta = 0; - gint64 adj_base_time = 0; - GstClock *curr_clock = NULL; - GstClockTime curr_time = 0; - gboolean query_ret = TRUE; - int result = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail ( player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail ( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED); - - // debug_log("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time); - - if ((video_time < 0) || (player->doing_seek)) - { - debug_log("skip setting master clock. %lld", video_time); - goto EXIT; - } - - mainbin = player->pipeline->mainbin; - - curr_clock = gst_pipeline_get_clock (GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst)); - curr_time = gst_clock_get_time (curr_clock); - - current_state = MMPLAYER_CURRENT_STATE(player); - - if ( current_state == MM_PLAYER_STATE_PLAYING ) - query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position); - - if ( ( current_state != MM_PLAYER_STATE_PLAYING ) || - ( !query_ret )) - { - position = player->last_position; - debug_log ("query fail. %lld", position); - } - - clock*= GST_USECOND; - clock_delta *= GST_USECOND; - - api_delta = clock - curr_time; - if ((player->video_share_api_delta == 0 ) || (player->video_share_api_delta > api_delta)) - { - player->video_share_api_delta = api_delta; - } - else - { - clock_delta += (api_delta - player->video_share_api_delta); - } - - if ((player->video_share_clock_delta == 0 ) || (player->video_share_clock_delta > clock_delta)) - { - player->video_share_clock_delta = (gint64)clock_delta; - - position_delta = (position/GST_USECOND) - video_time; - position_delta *= GST_USECOND; - - adj_base_time = position_delta; - debug_log ("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time); - - } - else - { - gint64 new_play_time = 0; - gint64 network_delay =0; - - video_time *= GST_USECOND; - - network_delay = clock_delta - player->video_share_clock_delta; - new_play_time = video_time + network_delay; - - adj_base_time = position - new_play_time; - - debug_log ("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)", - network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay); - } - - /* Adjust Current Stream Time with base_time of sink - * 1. Set Start time to CLOCK NONE, to control the base time by MSL - * 2. Set new base time - * if adj_base_time is positive value, the stream time will be decreased. - * 3. If seek event is occurred, the start time will be reset. */ - if ((player->pipeline->audiobin) && - (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) - { - start_time_audio = gst_element_get_start_time (player->pipeline->audiobin[MMPLAYER_A_SINK].gst); - - if (start_time_audio != GST_CLOCK_TIME_NONE) - { - debug_log ("audio sink : gst_element_set_start_time -> NONE"); - gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE); - } - - base_time = gst_element_get_base_time (player->pipeline->audiobin[MMPLAYER_A_SINK].gst); - } - - if ((player->pipeline->videobin) && - (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) - { - start_time_video = gst_element_get_start_time (player->pipeline->videobin[MMPLAYER_V_SINK].gst); - - if (start_time_video != GST_CLOCK_TIME_NONE) - { - debug_log ("video sink : gst_element_set_start_time -> NONE"); - gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE); - } - - // if videobin exist, get base_time from videobin. - base_time = gst_element_get_base_time (player->pipeline->videobin[MMPLAYER_V_SINK].gst); - } - - new_base_time = base_time + adj_base_time; - - if ((player->pipeline->audiobin) && - (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) - gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time); - - if ((player->pipeline->videobin) && - (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) - gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time); - -EXIT: - MMPLAYER_FLEAVE(); - - return result; -} - -int -_mmplayer_get_video_share_master_clock( MMHandleType hplayer, - long long *video_time, - long long *media_clock, - long long *audio_time) -{ - mm_player_t* player = (mm_player_t*) hplayer; - MMPlayerGstElement* mainbin = NULL; - GstClock *curr_clock = NULL; - MMPlayerStateType current_state = MM_PLAYER_STATE_NONE; - gint64 position = 0; - gboolean query_ret = TRUE; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail ( player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail ( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED); - - return_val_if_fail ( video_time, MM_ERROR_COMMON_INVALID_ARGUMENT ); - return_val_if_fail ( media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT ); - return_val_if_fail ( audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT ); - - mainbin = player->pipeline->mainbin; - - curr_clock = gst_pipeline_get_clock (GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst)); - - current_state = MMPLAYER_CURRENT_STATE(player); - - if ( current_state != MM_PLAYER_STATE_PAUSED ) - query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position); - - if ( ( current_state == MM_PLAYER_STATE_PAUSED ) || - ( !query_ret )) - { - position = player->last_position; - } - - *media_clock = *video_time = *audio_time = (position/GST_USECOND); - - debug_log("media_clock: %lld, video_time: %lld (us)", *media_clock, *video_time); - - if (curr_clock) - gst_object_unref (curr_clock); - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -int -_mmplayer_get_video_rotate_angle(MMHandleType hplayer, int *angle) -{ - mm_player_t* player = (mm_player_t*) hplayer; - int org_angle = 0; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - return_val_if_fail ( angle, MM_ERROR_COMMON_INVALID_ARGUMENT ); - - if (player->v_stream_caps) - { - GstStructure *str = NULL; - - str = gst_caps_get_structure (player->v_stream_caps, 0); - if ( !gst_structure_get_int (str, "orientation", &org_angle)) - { - debug_log ("missing 'orientation' field in video caps"); - } - } - - debug_log("orientation: %d", org_angle); - *angle = org_angle; - - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; -} - -gboolean -__mmplayer_is_streaming(mm_player_t* player) -{ - gboolean result = FALSE; - - MMPLAYER_FENTER(); - - return_val_if_fail (player, FALSE); - result = __is_streaming (player) ; - - MMPLAYER_FLEAVE(); - return result; -} - -static gboolean -__mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element) -{ - return_val_if_fail (player, FALSE); - return_val_if_fail (element, FALSE); - - gchar *factory_name = GST_OBJECT_NAME (gst_element_get_factory(element)); - gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2]; - - int idx = 0; - - for ( idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++ ) - { - if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) - { - debug_log("dump [%s] sink pad", player->ini.dump_element_keyword[idx]); - mm_player_dump_t *dump_s; - dump_s = g_malloc (sizeof(mm_player_dump_t)); - - if (dump_s == NULL) - { - debug_error ("malloc fail"); - return FALSE; - } - - dump_s->dump_element_file = NULL; - dump_s->dump_pad = NULL; - dump_s->dump_pad = gst_element_get_static_pad (element, "sink"); - - if (dump_s->dump_pad) - { - memset (dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2); - sprintf (dump_file_name, "%s/%s_sink_pad.dump", player->ini.dump_element_path, player->ini.dump_element_keyword[idx]); - dump_s->dump_element_file = fopen(dump_file_name,"w+"); - dump_s->probe_handle_id = gst_pad_add_probe (dump_s->dump_pad, GST_PAD_PROBE_TYPE_BUFFER, __mmplayer_dump_buffer_probe_cb, dump_s->dump_element_file, NULL); - /* add list for removed buffer probe and close FILE */ - player->dump_list = g_list_append (player->dump_list, dump_s); - debug_log ("%s sink pad added buffer probe for dump", factory_name); - return TRUE; - } - else - { - g_free(dump_s); - dump_s = NULL; - debug_error ("failed to get %s sink pad added", factory_name); - } - - - } - } - return FALSE; -} - -static GstPadProbeReturn -__mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data) -{ - FILE *dump_data = (FILE *) u_data; -// int written = 0; - GstBuffer *buffer = gst_pad_probe_info_get_buffer(info); - GstMapInfo probe_info = GST_MAP_INFO_INIT; - - return_val_if_fail ( dump_data, FALSE ); - - gst_buffer_map(buffer, &probe_info, GST_MAP_READ); - -// debug_log ("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS( GST_BUFFER_TIMESTAMP(buffer))); - - fwrite ( probe_info.data, 1, probe_info.size , dump_data); - - return GST_PAD_PROBE_OK; -} - -static void -__mmplayer_release_dump_list (GList *dump_list) -{ - if (dump_list) - { - GList *d_list = dump_list; - for ( ;d_list ; d_list = g_list_next(d_list)) - { - mm_player_dump_t *dump_s = d_list->data; - if (dump_s->dump_pad) - { - if (dump_s->probe_handle_id) - { - gst_pad_remove_probe (dump_s->dump_pad, dump_s->probe_handle_id); - } - - } - if (dump_s->dump_element_file) - { - fclose(dump_s->dump_element_file); - dump_s->dump_element_file = NULL; - } - MMPLAYER_FREEIF(dump_s); - } - g_list_free(dump_list); - dump_list = NULL; - } -} - -int -_mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist) -{ - mm_player_t* player = (mm_player_t*) hplayer; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - return_val_if_fail ( exist, MM_ERROR_INVALID_ARGUMENT ); - - *exist = player->has_closed_caption; - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -int -_mmplayer_enable_media_packet_video_stream(MMHandleType hplayer, bool enable) -{ - mm_player_t* player = (mm_player_t*) hplayer; - - MMPLAYER_FENTER(); - - return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail (enable == TRUE || enable == FALSE, MM_ERROR_INVALID_ARGUMENT); - if(enable) - player->bufmgr = tbm_bufmgr_init(-1); - else { - tbm_bufmgr_deinit(player->bufmgr); - player->bufmgr = NULL; - } - - player->set_mode.media_packet_video_stream = enable; - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -void * _mm_player_media_packet_video_stream_internal_buffer_ref(void *buffer) -{ - void * ret = NULL - MMPLAYER_FENTER(); - /* increase ref count of gst buffer */ - if (buffer) - ret = gst_buffer_ref((GstBuffer *)buffer); - - MMPLAYER_FLEAVE(); - return ret; -} - -void _mm_player_media_packet_video_stream_internal_buffer_unref(void *buffer) -{ - MMPLAYER_FENTER(); - if (buffer) { - gst_buffer_unref((GstBuffer *)buffer); - buffer = NULL; - } - MMPLAYER_FLEAVE(); -} - -void -__gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data) -{ - mm_player_t *player = (mm_player_t*)user_data; - MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO; - - return_if_fail ( player ); - - debug_msg("app-src: feed audio\n"); - - if (player->media_stream_buffer_status_cb[type]) - { - player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, player->buffer_cb_user_param); - } -} - -void -__gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data) -{ - mm_player_t *player = (mm_player_t*)user_data; - MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO; - - return_if_fail ( player ); - - debug_msg("app-src: feed video\n"); - - if (player->media_stream_buffer_status_cb[type]) - { - player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, player->buffer_cb_user_param); - } -} - -void -__gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data) -{ - mm_player_t *player = (mm_player_t*)user_data; - MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT; - - return_if_fail ( player ); - - debug_msg("app-src: feed subtitle\n"); - - if (player->media_stream_buffer_status_cb[type]) - { - player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, player->buffer_cb_user_param); - } -} - -void -__gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data) -{ - mm_player_t *player = (mm_player_t*)user_data; - MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO; - - return_if_fail ( player ); - - debug_msg("app-src: audio buffer is full.\n"); - - if (player->media_stream_buffer_status_cb[type]) - { - player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, player->buffer_cb_user_param); - } -} - -void -__gst_appsrc_enough_video_data(GstElement *element, gpointer user_data) -{ - mm_player_t *player = (mm_player_t*)user_data; - MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO; - - return_if_fail ( player ); - - debug_msg("app-src: video buffer is full.\n"); - - if (player->media_stream_buffer_status_cb[type]) - { - player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, player->buffer_cb_user_param); - } -} - -gboolean -__gst_seek_audio_data (GstElement * appsrc, guint64 position, gpointer user_data) -{ - mm_player_t *player = (mm_player_t*)user_data; - MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO; - - return_val_if_fail( player, FALSE ); - - debug_log("app-src: seek audio data\n"); - - if (player->media_stream_seek_data_cb[type]) - { - player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param); - } - - return TRUE; -} - -gboolean -__gst_seek_video_data (GstElement * appsrc, guint64 position, gpointer user_data) -{ - mm_player_t *player = (mm_player_t*)user_data; - MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO; - - return_val_if_fail( player, FALSE ); - - debug_log("app-src: seek video data\n"); - - if (player->media_stream_seek_data_cb[type]) - { - player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param); - } - - return TRUE; -} - -gboolean -__gst_seek_subtitle_data (GstElement * appsrc, guint64 position, gpointer user_data) -{ - mm_player_t *player = (mm_player_t*)user_data; - MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT; - - return_val_if_fail( player, FALSE ); - - debug_log("app-src: seek subtitle data\n"); - - if (player->media_stream_seek_data_cb[type]) - { - player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param); - } - - return TRUE; -} - -int -_mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel) -{ - mm_player_t* player = (mm_player_t*) hplayer; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - - player->pcm_samplerate = samplerate; - player->pcm_channel = channel; - - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; -} diff --git a/src/mm_player_sound_focus.c b/src/mm_player_sound_focus.c deleted file mode 100755 index e9f2818..0000000 --- a/src/mm_player_sound_focus.c +++ /dev/null @@ -1,295 +0,0 @@ -/* - * libmm-player - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , YeJin Cho , - * Seungbae Shin , YoungHwan An - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include -#include -#include -#include - -#include "mm_player_utils.h" -#include "mm_player_priv.h" -#include "mm_player_sound_focus.h" - -#define MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(x_player_sound_focus) \ -do \ -{ \ - if (!x_player_sound_focus) \ - { \ - debug_log("no sound focus instance");\ - return MM_ERROR_SOUND_NOT_INITIALIZED; \ - } \ -}while(0); - -void __mmplayer_sound_signal_callback (mm_sound_signal_name_t signal, int value, void *user_data) -{ - MMPlayerSoundFocus *sound_focus = (MMPlayerSoundFocus*)user_data; - - debug_log("sound signal callback %d / %d", signal, value); - - if (signal == MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS) - { - if (value == 1) - { - if (sound_focus->watch_id > 0) - { - debug_log("unset the focus watch cb"); - - mm_sound_unset_focus_watch_callback(sound_focus->watch_id); - sound_focus->watch_id = 0; - /* - if (sound_focus->subscribe_id > 0) - mm_sound_unsubscribe_signal(sound_focus->subscribe_id); - */ - } - } - } -} - -const gchar * -__mmplayer_sound_get_stream_type(gint type) -{ - switch ( type ) - { - case MM_SESSION_TYPE_CALL: - case MM_SESSION_TYPE_VIDEOCALL: - case MM_SESSION_TYPE_VOIP: - return "ringtone-voip"; - case MM_SESSION_TYPE_MEDIA: - return "media"; - case MM_SESSION_TYPE_NOTIFY: - return "notification"; - case MM_SESSION_TYPE_ALARM: - return "alarm"; - case MM_SESSION_TYPE_EMERGENCY: - return "emergency"; - default: - debug_warning("unexpected case!\n"); - return "media"; - } - - return "media"; -} - -int -_mmplayer_sound_acquire_focus(MMPlayerSoundFocus* sound_focus) -{ - int ret = MM_ERROR_NONE; - const gchar *stream_type = NULL; - - MMPLAYER_FENTER(); - MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus); - - if (sound_focus->acquired) - { - debug_warning("focus is already acquired. can't acquire again."); - return MM_ERROR_NONE; - } - - stream_type = __mmplayer_sound_get_stream_type(sound_focus->session_type); - - if ((!strstr(stream_type, "media")) || - (sound_focus->session_flags & MM_SESSION_OPTION_PAUSE_OTHERS)) - { - - ret = mm_sound_acquire_focus(sound_focus->focus_id, FOCUS_FOR_BOTH, NULL); - if (ret != MM_ERROR_NONE) - { - debug_error("failed to acquire sound focus\n"); - return ret; - } - - sound_focus->acquired = TRUE; - } - - MMPLAYER_FLEAVE(); - return ret; -} - -int -_mmplayer_sound_release_focus(MMPlayerSoundFocus* sound_focus) -{ - int ret = MM_ERROR_NONE; - const gchar *stream_type = NULL; - - MMPLAYER_FENTER(); - MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus); - - if (!sound_focus->acquired) - { - debug_warning("focus is not acquired. no need to release."); - return MM_ERROR_NONE; - } - - stream_type = __mmplayer_sound_get_stream_type(sound_focus->session_type); - - if ((!strstr(stream_type, "media")) || - (sound_focus->session_flags & MM_SESSION_OPTION_PAUSE_OTHERS)) - { - ret = mm_sound_release_focus(sound_focus->focus_id, FOCUS_FOR_BOTH, NULL); - if (ret != MM_ERROR_NONE) - { - debug_error("failed to release sound focus\n"); - return ret; - } - - sound_focus->acquired = FALSE; - } - - MMPLAYER_FLEAVE(); - return MM_ERROR_NONE; -} - -gint -_mmplayer_sound_register(MMPlayerSoundFocus* sound_focus, - mm_sound_focus_changed_cb focus_cb, mm_sound_focus_changed_watch_cb watch_cb, void* param) -{ - gint pid = -1; - gint ret = MM_ERROR_NONE; - const gchar *stream_type = NULL; - - MMPLAYER_FENTER(); - MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus); - - /* check if it's running on the media_server */ - if (sound_focus->pid > 0) - { - pid = sound_focus->pid; - debug_log("mm-player is running on different process. Just faking pid to [%d]. :-p\n", pid); - } - - /* read session information */ - ret = _mm_session_util_read_information(pid, &sound_focus->session_type, &sound_focus->session_flags); - if (ret != MM_ERROR_NONE) - { - debug_error("Read Session Type failed. ret:0x%X \n", ret); - - if (ret == MM_ERROR_INVALID_HANDLE) - { - int sig_value = 0; - - mm_sound_get_signal_value(MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS, &sig_value); - debug_warning("internal focus signal value=%d, id=%d\n", sig_value, sound_focus->subscribe_id); - - if ((sig_value == 0) && (sound_focus->subscribe_id == 0)) - { - ret = mm_sound_subscribe_signal(MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS, &sound_focus->subscribe_id, - (mm_sound_signal_callback)__mmplayer_sound_signal_callback, (void*)sound_focus); - if (ret != MM_ERROR_NONE) - { - debug_error("mm_sound_subscribe_signal is failed\n"); - return MM_ERROR_POLICY_BLOCKED; - } - - debug_log("register focus watch callback for the value is 0, sub_cb id %d\n", sound_focus->subscribe_id); - - ret = mm_sound_set_focus_watch_callback(FOCUS_FOR_BOTH, watch_cb, (void*)param, &sound_focus->watch_id); - if (ret != MM_ERROR_NONE) - { - debug_error("mm_sound_set_focus_watch_callback is failed\n"); - return MM_ERROR_POLICY_BLOCKED; - } - } - - return MM_ERROR_NONE; - } - else - { - return MM_ERROR_POLICY_BLOCKED; - } - } - - /* interpret session information */ - stream_type = __mmplayer_sound_get_stream_type(sound_focus->session_type); - debug_log("fid [%d] wid [%d] type[%s], flags[0x%02X]\n", - sound_focus->focus_id, sound_focus->watch_id, stream_type, sound_focus->session_flags); - - if (sound_focus->focus_id == 0) - { - /* get unique id */ - ret = mm_sound_focus_get_id(&sound_focus->focus_id); - if (ret != MM_ERROR_NONE) - { - debug_error("failed to get unique focus id\n"); - return MM_ERROR_POLICY_BLOCKED; - } - - /* register sound focus callback */ - ret = mm_sound_register_focus(sound_focus->focus_id, stream_type, focus_cb, (void*)param); - if (ret != MM_ERROR_NONE) - { - debug_error("mm_sound_register_focus is failed\n"); - return MM_ERROR_POLICY_BLOCKED; - } - } - - if ((sound_focus->watch_id == 0) && - (strstr(stream_type, "media")) && - !(sound_focus->session_flags & ASM_SESSION_OPTION_PAUSE_OTHERS) && - !(sound_focus->session_flags & ASM_SESSION_OPTION_UNINTERRUPTIBLE)) - { - debug_log("register focus watch callback\n"); - - ret = mm_sound_set_focus_watch_callback(FOCUS_FOR_BOTH, watch_cb, (void*)param, &sound_focus->watch_id); - if (ret != MM_ERROR_NONE) - { - debug_error("mm_sound_set_focus_watch_callback is failed\n"); - return MM_ERROR_POLICY_BLOCKED; - } - } - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - -gint -_mmplayer_sound_unregister(MMPlayerSoundFocus* sound_focus) -{ - MMPLAYER_FENTER(); - - MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus); - - debug_log("unregister sound focus callback\n"); - - if (sound_focus->focus_id > 0) - { - mm_sound_unregister_focus(sound_focus->focus_id); - sound_focus->focus_id = 0; - } - - if (sound_focus->watch_id > 0) - { - mm_sound_unset_focus_watch_callback(sound_focus->watch_id); - sound_focus->watch_id = 0; - } - - if (sound_focus->subscribe_id > 0) - { - mm_sound_unsubscribe_signal(sound_focus->subscribe_id); - sound_focus->subscribe_id = 0; - } - - MMPLAYER_FLEAVE(); - - return MM_ERROR_NONE; -} - diff --git a/src/mm_player_streaming.c b/src/mm_player_streaming.c deleted file mode 100755 index 151ce8b..0000000 --- a/src/mm_player_streaming.c +++ /dev/null @@ -1,1115 +0,0 @@ -/* - * libmm-player - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , YeJin Cho , - * Seungbae Shin , YoungHwan An - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include -#include "mm_player_utils.h" -#include "mm_player_streaming.h" - -#define TO_THE_END 0 - -typedef struct{ - gint byte_in_rate; // byte - gint byte_out_rate; // byte - gdouble time_rate; // second - guint buffer_criteria; // byte -}streaming_bitrate_info_t; - -typedef struct{ - gint64 position; // ns - gint64 duration; // ns - guint64 content_size; // bytes -}streaming_content_info_t; - -typedef struct{ - guint buffering_bytes; // bytes - gdouble buffering_time; // second - gdouble percent_byte; - gdouble percent_time; -}streaming_buffer_info_t; - -static void streaming_check_buffer_percent(gdouble in_low, gdouble in_high, gdouble *out_low, gdouble *out_high); -static void streaming_set_buffer_percent(mm_player_streaming_t* streamer, BufferType type, gdouble low_percent, gdouble high_percent_byte, gdouble high_percent_time); -static void streaming_set_queue2_queue_type (mm_player_streaming_t* streamer, gboolean use_file, gchar * file_path, guint64 content_size); -static void streaming_set_buffer_size(mm_player_streaming_t* streamer, BufferType type, guint buffering_bytes, gdouble buffering_time); -static void streaming_update_buffering_status(mm_player_streaming_t* streamer, GstMessage *buffering_msg, gint64 position); -static void streaming_get_current_bitrate_info( mm_player_streaming_t* streamer, - GstMessage *buffering_msg, - streaming_content_info_t content_info, - streaming_bitrate_info_t* bitrate_info); -static void -streaming_handle_fixed_buffering_mode( mm_player_streaming_t* streamer, - gint byte_out_rate, - gdouble fixed_buffering_time, - streaming_buffer_info_t* buffer_info); -static void -streaming_handle_adaptive_buffering_mode( mm_player_streaming_t* streamer, - streaming_content_info_t content_info, - streaming_bitrate_info_t bitrate_info, - streaming_buffer_info_t* buffer_info, - gint expected_play_time); -static void -streaming_update_buffer_setting ( mm_player_streaming_t* streamer, - GstMessage *buffering_msg, - guint64 content_size, - gint64 position, - gint64 duration); - -mm_player_streaming_t * -__mm_player_streaming_create (void) -{ - mm_player_streaming_t *streamer = NULL; - - MMPLAYER_FENTER(); - - streamer = (mm_player_streaming_t *) malloc (sizeof (mm_player_streaming_t)); - if (!streamer) - { - debug_error ("fail to create streaming player handle..\n"); - return NULL; - } - - memset(streamer, 0, sizeof(mm_player_streaming_t)); - - MMPLAYER_FLEAVE(); - - return streamer; -} - -static void -streaming_buffer_initialize (streaming_buffer_t* buffer_handle, gboolean buffer_init) -{ - if (buffer_init) - buffer_handle->buffer = NULL; - - buffer_handle->buffering_bytes = DEFAULT_BUFFER_SIZE_BYTES; - buffer_handle->buffering_time = DEFAULT_BUFFERING_TIME; - buffer_handle->buffer_low_percent = DEFAULT_BUFFER_LOW_PERCENT; - buffer_handle->buffer_high_percent = DEFAULT_BUFFER_HIGH_PERCENT; - buffer_handle->is_live = FALSE; - -} - -void __mm_player_streaming_initialize (mm_player_streaming_t* streamer) -{ - MMPLAYER_FENTER(); - - streamer->streaming_buffer_type = BUFFER_TYPE_DEFAULT; // multi-queue - - streaming_buffer_initialize(&(streamer->buffer_handle[BUFFER_TYPE_MUXED]), TRUE); - streaming_buffer_initialize(&(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]), TRUE); - - streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_ADAPTIVE; - streamer->buffering_req.is_pre_buffering = FALSE; - streamer->buffering_req.initial_second = 0; - streamer->buffering_req.runtime_second = 0; - - streamer->default_val.buffering_monitor = FALSE; - streamer->default_val.buffering_time = DEFAULT_BUFFERING_TIME; - - streamer->buffer_avg_bitrate = 0; - streamer->buffer_max_bitrate = 0; - streamer->need_update = FALSE; - streamer->need_sync = FALSE; - - streamer->is_buffering = FALSE; - streamer->is_buffering_done = FALSE; - streamer->is_adaptive_streaming = FALSE; - streamer->buffering_percent = -1; - - MMPLAYER_FLEAVE(); - return; -} - -void __mm_player_streaming_deinitialize (mm_player_streaming_t* streamer) -{ - MMPLAYER_FENTER(); - return_if_fail(streamer); - - streamer->streaming_buffer_type = BUFFER_TYPE_DEFAULT; // multi-queue - - streaming_buffer_initialize(&(streamer->buffer_handle[BUFFER_TYPE_MUXED]), FALSE); - streaming_buffer_initialize(&(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]), FALSE); - - streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_ADAPTIVE; - streamer->buffering_req.is_pre_buffering = FALSE; - streamer->buffering_req.initial_second = 0; - streamer->buffering_req.runtime_second = 0; - - streamer->default_val.buffering_monitor = FALSE; - streamer->default_val.buffering_time = DEFAULT_BUFFERING_TIME; - - streamer->buffer_avg_bitrate = 0; - streamer->buffer_max_bitrate = 0; - streamer->need_update = FALSE; - streamer->need_sync = FALSE; - - streamer->is_buffering = FALSE; - streamer->is_buffering_done = FALSE; - streamer->is_adaptive_streaming = FALSE; - - streamer->buffering_percent = -1; - - MMPLAYER_FLEAVE(); - return; -} - -void __mm_player_streaming_destroy (mm_player_streaming_t* streamer) -{ - MMPLAYER_FENTER(); - - if(streamer) - { - g_free (streamer); - streamer = NULL; - } - - MMPLAYER_FLEAVE(); - - return; -} - -void __mm_player_streaming_set_content_bitrate(mm_player_streaming_t* streamer, guint max_bitrate, guint avg_bitrate) -{ - MMPLAYER_FENTER(); - - return_if_fail(streamer); - - /* Note : Update buffering criterion bytes - * 1. maximum bitrate is considered first. - * 2. average bitrage * 3 is next. - * 3. if there are no updated bitrate, use default buffering limit. - */ - if (max_bitrate > 0 && streamer->buffer_max_bitrate != max_bitrate) - { - debug_log("set maximum bitrate(%dbps).\n", max_bitrate); - streamer->buffer_max_bitrate = max_bitrate; - if (streamer->buffering_req.is_pre_buffering == FALSE) - { - streamer->need_update = TRUE; - } - else - { - debug_log("pre-buffering...\n"); - - if (IS_MUXED_BUFFERING_MODE(streamer)) - streaming_update_buffer_setting(streamer, NULL, 0, 0, 0); - } - } - - if (avg_bitrate > 0 && streamer->buffer_avg_bitrate != avg_bitrate) - { - debug_log("set averate bitrate(%dbps).\n", avg_bitrate); - streamer->buffer_avg_bitrate = avg_bitrate; - - if (streamer->buffering_req.is_pre_buffering == FALSE) - { - streamer->need_update = TRUE; - } - else - { - debug_log("pre-buffering...\n"); - - if (IS_MUXED_BUFFERING_MODE(streamer)) - streaming_update_buffer_setting(streamer, NULL, 0, 0, 0); - } - } - - MMPLAYER_FLEAVE(); - return; -} - -static void -streaming_check_buffer_percent(gdouble in_low, gdouble in_high, gdouble *out_low, gdouble *out_high) -{ - gdouble buffer_low_percent = DEFAULT_BUFFER_LOW_PERCENT; - gdouble buffer_high_percent = DEFAULT_BUFFER_HIGH_PERCENT; - - MMPLAYER_FENTER(); - - return_if_fail(out_low && out_high); - - if (in_low <= MIN_BUFFER_PERCENT || in_low >= MAX_BUFFER_PERCENT) - { - debug_warning("buffer low percent is out of range. use defaut value."); - } - else - { - buffer_low_percent = in_low; - } - - if (in_high <= MIN_BUFFER_PERCENT || in_high >= MAX_BUFFER_PERCENT) - { - debug_warning("buffer high percent is out of range. use defaut value."); - } - else - { - buffer_high_percent = in_high; - } - - if (buffer_high_percent <= buffer_low_percent) - buffer_high_percent = buffer_low_percent + 1.0; - - debug_log("set buffer percent to %2.3f ~ %2.3f.", buffer_low_percent, buffer_high_percent); - - *out_low = buffer_low_percent; - *out_high = buffer_high_percent; -} - -static void -streaming_set_buffer_percent( mm_player_streaming_t* streamer, - BufferType type, - gdouble low_percent, - gdouble high_percent_byte, - gdouble high_percent_time) -{ - gdouble confirmed_low = DEFAULT_BUFFER_LOW_PERCENT; - gdouble confirmed_high = DEFAULT_BUFFER_HIGH_PERCENT; - gdouble high_percent = 0.0; - - streaming_buffer_t* buffer_handle = NULL; - gchar* factory_name = NULL; - - MMPLAYER_FENTER(); - return_if_fail(streamer); - return_if_fail(type < BUFFER_TYPE_MAX); - - buffer_handle = &(streamer->buffer_handle[type]); - if (!(buffer_handle && buffer_handle->buffer)) - { - debug_error("buffer_handle->buffer is NULL!"); - return; - } - - factory_name = GST_OBJECT_NAME(gst_element_get_factory(buffer_handle->buffer)); - - if (!factory_name) - { - debug_error("Fail to get factory name!"); - return; - } - - if (type == BUFFER_TYPE_MUXED) - high_percent = high_percent_byte; - else - high_percent = MAX(high_percent_time, high_percent_byte); - - streaming_check_buffer_percent(low_percent, high_percent, &confirmed_low, &confirmed_high); - - /* if use-buffering is disabled, this settings do not have any meaning. */ - debug_log("target buffer elem : %s (%2.3f ~ %2.3f)", - GST_ELEMENT_NAME(buffer_handle->buffer), confirmed_low, confirmed_high); - - if ((confirmed_low == DEFAULT_BUFFER_LOW_PERCENT) || - (buffer_handle->buffer_low_percent != confirmed_low)) - { - g_object_set (G_OBJECT(buffer_handle->buffer), "low-percent", (gint)confirmed_low, NULL); - } - - if ((confirmed_high == DEFAULT_BUFFER_HIGH_PERCENT) || - (buffer_handle->buffer_high_percent != confirmed_high)) - { - g_object_set (G_OBJECT(buffer_handle->buffer), "high-percent", (gint)confirmed_high, NULL); - } - - buffer_handle->buffer_low_percent = confirmed_low; - buffer_handle->buffer_high_percent = confirmed_high; - - MMPLAYER_FLEAVE(); - return; -} - -static void -streaming_set_queue2_queue_type (mm_player_streaming_t* streamer, gboolean use_file, gchar * file_path, guint64 content_size) -{ - streaming_buffer_t* buffer_handle = NULL; - guint64 storage_available_size = 0L; //bytes - guint64 file_buffer_size = 0L; //bytes - gchar file_buffer_name[MM_MAX_URL_LEN] = {0}; - struct statfs buf = {0}; - gchar* factory_name = NULL; - - MMPLAYER_FENTER(); - return_if_fail(streamer); - return_if_fail(streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer); - - buffer_handle = &(streamer->buffer_handle[BUFFER_TYPE_MUXED]); - - if (!(buffer_handle && buffer_handle->buffer)) - { - debug_error("buffer_handle->buffer is NULL!"); - return; - } - - factory_name = GST_OBJECT_NAME(gst_element_get_factory(buffer_handle->buffer)); - - if (!factory_name) - { - debug_error("Fail to get factory name!"); - return; - } - - debug_log("target buffer elem : %s", GST_ELEMENT_NAME(buffer_handle->buffer)); - - if (!g_strrstr(factory_name, "queue2")) - { - debug_log("only queue2 can use file buffer. not decodebin2 or multiQ\n"); - return; - } - - if ((!use_file) || (!g_strrstr(factory_name, "queue2"))) - { - debug_log("use memory for buffering. streaming is played on push-based. \n" - "buffering position would not be updated.\n" - "buffered data would be flushed after played.\n" - "seeking and getting duration could be failed due to file format."); - return; - } - - debug_log("[Queue2] use file for buffering. streaming is played on pull-based. \n"); - - if (!file_path || strlen(file_path) <= 0) - file_path = g_strdup(DEFAULT_FILE_BUFFER_PATH); - - g_snprintf(file_buffer_name, MM_MAX_URL_LEN, "%s/XXXXXX", file_path); - secure_debug_log("[Queue2] the buffering file name is %s.\n", file_buffer_name); - - if (statfs((const char *)file_path, &buf) < 0) - { - debug_warning ("[Queue2] fail to get availabe storage capacity. just use file buffer.\n"); - file_buffer_size = 0L; - } - else - { - storage_available_size = (guint64)buf.f_bavail * (guint64)buf.f_bsize; //bytes - - debug_log ("[Queue2] the number of available blocks : %"G_GUINT64_FORMAT - ", the block size is %"G_GUINT64_FORMAT".\n", - (guint64)buf.f_bavail, (guint64)buf.f_bsize); - - debug_log ("[Queue2] calculated availabe storage size is %" - G_GUINT64_FORMAT" Bytes.\n", storage_available_size); - - if (content_size <= 0 || content_size >= storage_available_size) - file_buffer_size = storage_available_size; - else - file_buffer_size = 0L; - } - - if (file_buffer_size>0) - debug_log("[Queue2] use file ring buffer for buffering."); - - g_object_set (G_OBJECT(buffer_handle->buffer), "temp-template", file_buffer_name, NULL); - g_object_set (G_OBJECT(buffer_handle->buffer), "ring-buffer-max-size", file_buffer_size, NULL); - - MMPLAYER_FLEAVE(); - return; -} - -static void -streaming_set_buffer_size(mm_player_streaming_t* streamer, BufferType type, guint buffering_bytes, gdouble buffering_time) -{ - streaming_buffer_t* buffer_handle = NULL; - - MMPLAYER_FENTER(); - - return_if_fail(streamer); - return_if_fail(buffering_bytes > 0); - return_if_fail(type < BUFFER_TYPE_MAX); - - buffer_handle = &(streamer->buffer_handle[type]); - - if (buffer_handle && buffer_handle->buffer) - { - if (g_strrstr(GST_ELEMENT_NAME(buffer_handle->buffer), "multiqueue")) - { - if (buffering_time <= 0) - buffering_time = GET_CURRENT_BUFFERING_TIME(buffer_handle); - - g_object_set (G_OBJECT(buffer_handle->buffer), - "max-size-bytes", GET_MAX_BUFFER_BYTES(streamer), /* mq size is fixed, control it with high/low percent value*/ - "max-size-time", ((guint)ceil(buffering_time) * GST_SECOND), - "max-size-buffers", 0, NULL); /* disable */ - - buffer_handle->buffering_time = buffering_time; - buffer_handle->buffering_bytes = GET_MAX_BUFFER_BYTES(streamer); - - debug_log("max-size-time : %f", buffering_time); - } - else /* queue2 */ - { - if (buffer_handle->is_live) - { - g_object_set (G_OBJECT(buffer_handle->buffer), - "max-size-bytes", buffering_bytes, - "max-size-time", (guint64)(buffering_time*GST_SECOND), - "max-size-buffers", 0, - "use-rate-estimate", TRUE, NULL); - } - else - { - g_object_set (G_OBJECT(buffer_handle->buffer), - "max-size-bytes", buffering_bytes, - "max-size-time", (guint64)0, - "max-size-buffers", 0, - "use-rate-estimate", FALSE, NULL); - } - - buffer_handle->buffering_bytes = buffering_bytes; - buffer_handle->buffering_time = buffering_time; - - debug_log("max-size-bytes : %d", buffering_bytes); - } - } - - MMPLAYER_FLEAVE(); - return; -} - -void __mm_player_streaming_set_queue2( mm_player_streaming_t* streamer, - GstElement* buffer, - gboolean use_buffering, - guint buffering_bytes, - gdouble buffering_time, - gdouble low_percent, - gdouble high_percent, - gboolean use_file, - gchar* file_path, - guint64 content_size) -{ - MMPLAYER_FENTER(); - return_if_fail(streamer); - - if (buffer) - { - debug_log("USE-BUFFERING : %s", (use_buffering)?"OOO":"XXX"); - - streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer = buffer; - - if (use_buffering) - { - streamer->streaming_buffer_type = BUFFER_TYPE_MUXED; - - if (content_size > 0) - { - if (streamer->buffering_req.initial_second > 0) - streamer->buffering_req.is_pre_buffering = TRUE; - else - streamer->buffering_req.initial_second = (gint)ceil(buffering_time); - } - else - { - debug_log("live streaming without mq"); - - streamer->buffer_handle[BUFFER_TYPE_MUXED].is_live = TRUE; - streamer->buffering_req.initial_second = buffering_time = DEFAULT_BUFFERING_TIME; - } - } - - g_object_set ( G_OBJECT (streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), "use-buffering", use_buffering, NULL ); - } - - streaming_set_buffer_size (streamer, BUFFER_TYPE_MUXED, buffering_bytes, buffering_time); - streaming_set_buffer_percent (streamer, BUFFER_TYPE_MUXED, low_percent, high_percent, 0); - streaming_set_queue2_queue_type (streamer, use_file, file_path, content_size); - - MMPLAYER_FLEAVE(); - return; -} - -void __mm_player_streaming_sync_property(mm_player_streaming_t* streamer, GstElement* decodebin) -{ - streaming_buffer_t* buffer_handle = NULL; - - MMPLAYER_FENTER(); - - return_if_fail ( streamer && decodebin ); - - buffer_handle = &(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]); - - if ((streamer->need_sync) && (streamer->streaming_buffer_type == BUFFER_TYPE_DEMUXED)) - { - g_object_set (G_OBJECT(decodebin), - "max-size-bytes", buffer_handle->buffering_bytes, - "max-size-time", (guint64)(ceil(buffer_handle->buffering_time) * GST_SECOND), - "low-percent", (gint)buffer_handle->buffer_low_percent, - "high-percent", (gint)buffer_handle->buffer_high_percent, NULL); - - } - - streamer->need_sync = FALSE; -} - -void __mm_player_streaming_set_multiqueue( mm_player_streaming_t* streamer, - GstElement* buffer, - gboolean use_buffering, - gdouble buffering_time, - gdouble low_percent, - gdouble high_percent) -{ - streaming_buffer_t* buffer_handle = NULL; - gdouble pre_buffering_time = 0.0; - - MMPLAYER_FENTER(); - return_if_fail(streamer); - - buffer_handle = &(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]); - pre_buffering_time = (gdouble)streamer->buffering_req.initial_second; - - if (buffer) - { - buffer_handle->buffer = buffer; - - if (use_buffering) - { - streamer->streaming_buffer_type = BUFFER_TYPE_DEMUXED; - - // during prebuffering by requirement, buffer setting should not be changed. - if (pre_buffering_time > 0) - streamer->buffering_req.is_pre_buffering = TRUE; - } - - g_object_set ( G_OBJECT (buffer_handle->buffer), "use-buffering", use_buffering, NULL ); - } - - debug_log ("pre_buffering: %2.2f, during playing: %2.2f\n", pre_buffering_time, buffering_time); - - if (pre_buffering_time <= 0.0) - { - pre_buffering_time = GET_DEFAULT_PLAYING_TIME(streamer); - streamer->buffering_req.initial_second = (gint)ceil(buffering_time); - } - - high_percent = (pre_buffering_time * 100) / GET_MAX_BUFFER_TIME(streamer); - debug_log ("high_percent %2.3f %%\n", high_percent); - - streaming_set_buffer_size (streamer, BUFFER_TYPE_DEMUXED, GET_MAX_BUFFER_BYTES(streamer), GET_MAX_BUFFER_TIME(streamer)); - streaming_set_buffer_percent (streamer, BUFFER_TYPE_DEMUXED, low_percent, 0, high_percent); - - streamer->need_sync = TRUE; - - MMPLAYER_FLEAVE(); - return; -} - -static void -streaming_get_current_bitrate_info( mm_player_streaming_t* streamer, - GstMessage *buffering_msg, - streaming_content_info_t content_info, - streaming_bitrate_info_t* bitrate_info) -{ - - GstQuery *query = NULL; - GstBufferingMode mode = GST_BUFFERING_STREAM; - gint in_rate = 0; - gint out_rate = 0; - gint64 buffering_left = -1; - - guint buffer_criteria = 0; - guint estimated_content_bitrate = 0; - - gdouble buffer_buffering_time = DEFAULT_BUFFERING_TIME; - - MMPLAYER_FENTER(); - - return_if_fail(streamer); - return_if_fail(bitrate_info); - - if ((buffering_msg == NULL) || - ((streamer->buffer_handle[BUFFER_TYPE_DEMUXED].buffer != NULL) && - (streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer != NULL) && - (buffering_msg->src == (GstObject *)streamer->buffer_handle[BUFFER_TYPE_DEMUXED].buffer))) - { - query = gst_query_new_buffering (GST_FORMAT_PERCENT); - - if (gst_element_query ((streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), query)) - { - gst_query_parse_buffering_stats (query, &mode, &in_rate, &out_rate, &buffering_left); - } - - gst_query_unref (query); - } - else - { - gst_message_parse_buffering_stats (buffering_msg, &mode, &in_rate, &out_rate, &buffering_left); - } - - debug_log ("Streaming Info : in %d, out %d, left %lld\n", in_rate, out_rate, buffering_left); - - if ((content_info.content_size > 0) && (content_info.duration > 0) && ((content_info.duration/GST_SECOND) > 0)) - estimated_content_bitrate = GET_BIT_FROM_BYTE((guint)(content_info.content_size / (content_info.duration/GST_SECOND))); - - if (streamer->buffer_max_bitrate > 0) - { - streamer->buffer_max_bitrate = MAX(streamer->buffer_max_bitrate, streamer->buffer_avg_bitrate); - streamer->buffer_max_bitrate = MAX(streamer->buffer_max_bitrate, estimated_content_bitrate); - - buffer_criteria = GET_BYTE_FROM_BIT(streamer->buffer_max_bitrate); - - if (streamer->buffer_avg_bitrate > estimated_content_bitrate) - out_rate = GET_BYTE_FROM_BIT(streamer->buffer_avg_bitrate); - else if (estimated_content_bitrate != 0) - out_rate = GET_BYTE_FROM_BIT(estimated_content_bitrate); - else - out_rate = GET_BYTE_FROM_BIT(streamer->buffer_max_bitrate/3); - - debug_log ("(max)content_max_byte_rate %d, byte_out_rate %d\n", buffer_criteria, out_rate); - } - else if (streamer->buffer_avg_bitrate > 0) - { - buffer_criteria = GET_BYTE_FROM_BIT(streamer->buffer_avg_bitrate * 3); - out_rate = GET_BYTE_FROM_BIT(MAX(streamer->buffer_avg_bitrate,estimated_content_bitrate)); - - debug_log ("(avg)content_max_byte_rate %d, byte_out_rate %d\n", buffer_criteria, out_rate); - } - else - { - debug_warning ("There is no content bitrate information\n"); - } - - if ((in_rate > 0) && (out_rate > 0)) - buffer_buffering_time = (gdouble)out_rate / (gdouble)in_rate; - else if ((in_rate <= 0) && (out_rate > 0)) - buffer_buffering_time = MAX_BUFFERING_TIME; - else - buffer_buffering_time = DEFAULT_BUFFERING_TIME; - - (*bitrate_info).byte_in_rate = in_rate; - (*bitrate_info).byte_out_rate = out_rate; - (*bitrate_info).time_rate = buffer_buffering_time; - (*bitrate_info).buffer_criteria = buffer_criteria; -} - -static void -streaming_handle_fixed_buffering_mode( mm_player_streaming_t* streamer, - gint byte_out_rate, - gdouble fixed_buffering_time, - streaming_buffer_info_t* buffer_info) -{ - streaming_buffer_t* buffer_handle = NULL; - - guint buffering_bytes = 0; - gdouble buffering_time = 0.0; - gdouble per_byte = 0.0; - gdouble per_time = 0.0; - - return_if_fail(streamer); - return_if_fail(buffer_info); - - buffer_handle = &(streamer->buffer_handle[streamer->streaming_buffer_type]); - buffering_time = fixed_buffering_time; - - debug_log ("buffering time: %2.2f sec, out rate: %d\n", buffering_time, byte_out_rate); - - if ((buffering_time > 0) && (byte_out_rate > 0)) - { - buffering_bytes = GET_NEW_BUFFERING_BYTE(byte_out_rate * buffering_time); - } - else - { - if (buffering_time <= 0) - buffering_time = GET_CURRENT_BUFFERING_TIME(buffer_handle); - - debug_warning ("content bitrate is not updated yet.\n"); - buffering_bytes = GET_CURRENT_BUFFERING_BYTE(buffer_handle); - } - - GET_PERCENT(buffering_time, GET_CURRENT_BUFFERING_TIME(buffer_handle), buffer_handle->buffer_high_percent, per_time); - GET_PERCENT(buffering_bytes, GET_CURRENT_BUFFERING_BYTE(buffer_handle), buffer_handle->buffer_high_percent, per_byte); - - debug_log ("bytes %d, time %f, per_byte %f, per_time %f\n", - buffering_bytes, buffering_time, per_byte, per_time); - - (*buffer_info).buffering_bytes = buffering_bytes; - (*buffer_info).buffering_time = buffering_time; - (*buffer_info).percent_byte = per_byte; - (*buffer_info).percent_time = per_time; -} - -static void -streaming_handle_adaptive_buffering_mode( mm_player_streaming_t* streamer, - streaming_content_info_t content_info, - streaming_bitrate_info_t bitrate_info, - streaming_buffer_info_t* buffer_info, - gint expected_play_time) -{ - streaming_buffer_t* buffer_handle = NULL; - - gint buffering_bytes = 0; - gint adj_buffering_bytes = 0; - gdouble buffer_buffering_time = 0.0; - gdouble per_byte = 0.0; - gdouble per_time = 0.0; - gdouble portion = 0.0; - gdouble default_buffering_time = 0.0; - - return_if_fail(streamer); - return_if_fail(buffer_info); - - debug_log ("pos %lld, dur %lld, size %lld, in/out:%d/%d, buffer_criteria:%d, time_rate:%f, need:%d sec\n", - content_info.position, content_info.duration, content_info.content_size, - bitrate_info.byte_in_rate, bitrate_info.byte_out_rate, - bitrate_info.buffer_criteria, bitrate_info.time_rate, expected_play_time); - - if (((expected_play_time == TO_THE_END) && (content_info.position <= 0)) || - (content_info.duration <= 0) || - (content_info.content_size <= 0)) - { - debug_warning ("keep previous setting.\n"); - return; - } - - if ((bitrate_info.byte_out_rate <= 0) || (bitrate_info.buffer_criteria == 0)) - { - debug_warning ("keep previous setting.\n"); - return; - } - - buffer_handle = &(streamer->buffer_handle[streamer->streaming_buffer_type]); - - if (bitrate_info.byte_in_rate < bitrate_info.byte_out_rate) - { - if (expected_play_time != TO_THE_END) - portion = (double)(expected_play_time * GST_SECOND) / (double)content_info.duration; - else - portion = (1 - (double)content_info.position/(double)content_info.duration); - - buffering_bytes = GET_NEW_BUFFERING_BYTE(((double)content_info.content_size * portion) \ - * (1 - (double)bitrate_info.byte_in_rate/(double)bitrate_info.byte_out_rate)); - } - else - { - /* buffering_bytes will be set as streamer->default_val.buffering_time * - * receiving rate is bigger than avg content bitrate - * so there is no reason to buffering. if the buffering msg is posted - * in-rate or contents bitrate has wrong value. */ - debug_warning ("don't need to do buffering.\n"); - } - - if (buffering_bytes > 0) - buffer_buffering_time = (gdouble)buffering_bytes / (gdouble)bitrate_info.byte_out_rate; - - if (content_info.position <= 0) - { - /* if the buffer is filled under 50%, MSL use the original default buffering time. - if not, MSL use just 2 sec as a default buffering time. (to reduce initial buffering time) */ - default_buffering_time = streamer->default_val.buffering_time - (streamer->buffering_percent/50); - } - else - { - default_buffering_time = streamer->default_val.buffering_time; - } - - if (buffer_buffering_time < default_buffering_time) - { - debug_log ("adjusted time: %2.2f -> %2.2f\n", buffer_buffering_time, default_buffering_time); - debug_log ("adjusted bytes : %d or %d or %d\n", - buffering_bytes, - (gint)(bitrate_info.byte_out_rate * buffer_buffering_time), - (gint)(bitrate_info.buffer_criteria * buffer_buffering_time)); - - if (content_info.position > 0) - { - /* start monitoring the abmormal state */ - streamer->default_val.buffering_monitor = TRUE; - } - - buffer_buffering_time = default_buffering_time; - adj_buffering_bytes = GET_NEW_BUFFERING_BYTE(bitrate_info.byte_out_rate * (gint)ceil(buffer_buffering_time)); - buffering_bytes = MAX(buffering_bytes, adj_buffering_bytes); - } - - GET_PERCENT(buffering_bytes, GET_CURRENT_BUFFERING_BYTE(buffer_handle), buffer_handle->buffer_high_percent, per_byte); - GET_PERCENT(buffer_buffering_time, GET_CURRENT_BUFFERING_TIME(buffer_handle), buffer_handle->buffer_high_percent, per_time); - - debug_log ("monitor %d, bytes %d, time %f, per_byte %f, per_time %f\n", - streamer->default_val.buffering_monitor, - buffering_bytes, buffer_buffering_time, per_byte, per_time); - - (*buffer_info).buffering_bytes = buffering_bytes; - (*buffer_info).buffering_time = buffer_buffering_time; - (*buffer_info).percent_byte = per_byte; - (*buffer_info).percent_time = per_time; - -} - -static void -streaming_update_buffer_setting ( mm_player_streaming_t* streamer, - GstMessage *buffering_msg, // can be null - guint64 content_size, - gint64 position, - gint64 duration) -{ - streaming_buffer_t* buffer_handle = NULL; - MMPlayerBufferingMode buffering_mode = MM_PLAYER_BUFFERING_MODE_ADAPTIVE; - - streaming_buffer_info_t buffer_info; - streaming_content_info_t content_info; - streaming_bitrate_info_t bitrate_info; - - gdouble low_percent = 0.0; - - MMPLAYER_FENTER(); - - return_if_fail ( streamer ); - - memset(&buffer_info, 0x00, sizeof(streaming_buffer_info_t)); - memset(&content_info, 0x00, sizeof(streaming_content_info_t)); - memset(&bitrate_info, 0x00, sizeof(streaming_bitrate_info_t)); - - buffer_handle = &(streamer->buffer_handle[streamer->streaming_buffer_type]); - - if (streamer->buffering_req.is_pre_buffering == TRUE) - buffering_mode = MM_PLAYER_BUFFERING_MODE_FIXED; - else - buffering_mode = streamer->buffering_req.mode; - - buffer_info.buffering_bytes = buffer_handle->buffering_bytes; - buffer_info.buffering_time = buffer_handle->buffering_time; - buffer_info.percent_byte = buffer_handle->buffer_high_percent; - buffer_info.percent_time = buffer_handle->buffer_high_percent; - - content_info.position = position; - content_info.duration = duration; - content_info.content_size = content_size; - - streaming_get_current_bitrate_info(streamer, buffering_msg, content_info, &bitrate_info); - - debug_log ("buffering mode %d, new info in_r:%d, out_r:%d, cb:%d, bt:%f\n", - buffering_mode, bitrate_info.byte_in_rate, bitrate_info.byte_out_rate, - bitrate_info.buffer_criteria, bitrate_info.time_rate); - - /* calculate buffer low/high percent */ - low_percent = DEFAULT_BUFFER_LOW_PERCENT; - - /******************** - * (1) fixed mode * - ********************/ - - if (buffering_mode == MM_PLAYER_BUFFERING_MODE_FIXED) - { - gdouble buffering_time = 0.0; - - if (streamer->buffering_req.is_pre_buffering == TRUE) - buffering_time = (gdouble)streamer->buffering_req.initial_second; - else - buffering_time = (gdouble)streamer->buffering_req.runtime_second; - - streaming_handle_fixed_buffering_mode(streamer, bitrate_info.byte_out_rate, buffering_time, &buffer_info); - } - - /*********************************** - * (2) once mode for samsung link * - ***********************************/ - else if (buffering_mode == MM_PLAYER_BUFFERING_MODE_SLINK) - { - streaming_handle_adaptive_buffering_mode(streamer, content_info, bitrate_info, &buffer_info, TO_THE_END); - } - - /********************************* - * (3) adaptive mode (default) * - *********************************/ - else - { - gint expected_play_time = DEFAULT_PLAYING_TIME; - - if (streamer->buffering_req.runtime_second > 0) - { - expected_play_time = streamer->buffering_req.runtime_second; - } - else if ((position == 0) && (streamer->is_buffering)) - { - expected_play_time = streamer->buffering_req.initial_second; - } - - if (expected_play_time <= 0) - expected_play_time = DEFAULT_PLAYING_TIME; - - streaming_handle_adaptive_buffering_mode(streamer, content_info, bitrate_info, &buffer_info, expected_play_time); - - if (IS_MUXED_BUFFERING_MODE(streamer)) // even if new byte size is smaller than the previous one, time need to be updated. - buffer_handle->buffering_time = buffer_info.buffering_time; - } - - debug_log ("adj buffer(%d) %d->%d bytes/%2.2f->%2.2f sec\n", - streamer->streaming_buffer_type, - GET_CURRENT_BUFFERING_BYTE(buffer_handle), buffer_info.buffering_bytes, - GET_CURRENT_BUFFERING_TIME(buffer_handle), buffer_info.buffering_time); - - /* queue2 : bytes, multiqueue : time */ - if (((GET_CURRENT_BUFFERING_BYTE(buffer_handle) < buffer_info.buffering_bytes) && IS_MUXED_BUFFERING_MODE(streamer)) || - ((GET_CURRENT_BUFFERING_TIME(buffer_handle) < buffer_info.buffering_time) && IS_DEMUXED_BUFFERING_MODE(streamer))) - { - if (duration > 0 && position > 0) - { - gdouble buffering_time_limit = (gdouble)(duration - position)/GST_SECOND; - - if (buffer_info.buffering_time > buffering_time_limit) - buffer_info.buffering_time = buffering_time_limit; - } - - streaming_set_buffer_size(streamer, streamer->streaming_buffer_type, buffer_info.buffering_bytes, buffer_info.buffering_time); - } - - streaming_set_buffer_percent(streamer, streamer->streaming_buffer_type, low_percent, buffer_info.percent_byte, buffer_info.percent_time); - - debug_log("buffer setting: size %d, time %f, per %f\n", - GET_CURRENT_BUFFERING_BYTE(buffer_handle), - GET_CURRENT_BUFFERING_TIME(buffer_handle), - buffer_handle->buffer_high_percent); - - streamer->need_sync = TRUE; -} - -static void -streaming_adjust_min_threshold(mm_player_streaming_t* streamer, gint64 position) -{ -#define DEFAULT_TIME_PAD 1 /* sec */ - gint playing_time = 0; - - MMPLAYER_FENTER(); - - return_if_fail(streamer); - - playing_time = (gint)((position - streamer->default_val.prev_pos) / GST_SECOND); - - debug_log ("buffering monitor = %s\n", (streamer->default_val.buffering_monitor)?"ON":"OFF"); - debug_log ("playing_time ( %d sec) = %lld - %lld \n", playing_time, position, streamer->default_val.prev_pos); - debug_log ("default time : %2.3f, prev buffering t : %2.3f\n", - streamer->default_val.buffering_time, streamer->buffer_handle[streamer->streaming_buffer_type].buffering_time); - - if ((streamer->default_val.buffering_monitor) && (playing_time <= (gint)streamer->default_val.buffering_time)) - { - gint time_gap = 0; - time_gap = (gint)(streamer->default_val.buffering_time - DEFAULT_BUFFERING_TIME); - if (time_gap <= 0) - time_gap = DEFAULT_TIME_PAD; - - streamer->default_val.buffering_time += time_gap*2; - streamer->default_val.buffering_time = MIN(streamer->default_val.buffering_time, MAX_BUFFERING_TIME); - } - else - { - streamer->default_val.buffering_time = DEFAULT_BUFFERING_TIME; - } - - debug_log ("new default min value %2.3f \n", streamer->default_val.buffering_time); - - streamer->default_val.buffering_monitor = FALSE; - streamer->default_val.prev_pos = position; -} - -static void -streaming_update_buffering_status(mm_player_streaming_t* streamer, GstMessage *buffering_msg, gint64 position) -{ - gint buffer_percent = 0; - gboolean increased_per = TRUE; - - MMPLAYER_FENTER(); - - return_if_fail(streamer); - return_if_fail(buffering_msg); - - /* update when buffering has started. */ - if ( !streamer->is_buffering ) - { - streamer->is_buffering = TRUE; - streamer->is_buffering_done = FALSE; - streamer->buffering_percent = -1; - - if (!streamer->buffering_req.is_pre_buffering) - { - streamer->need_update = TRUE; - streaming_adjust_min_threshold(streamer, position); - } - } - - /* update buffer percent */ - gst_message_parse_buffering (buffering_msg, &buffer_percent); - - if (streamer->buffering_percent < buffer_percent) - { - debug_log ("[%s] buffering %d%%....\n", - GST_OBJECT_NAME(GST_MESSAGE_SRC(buffering_msg)), buffer_percent); - streamer->buffering_percent = buffer_percent; - } - else - { - increased_per = FALSE; - } - - if ((streamer->buffering_percent == MAX_BUFFER_PERCENT) || (streamer->is_buffering_done == TRUE)) - { - streamer->is_buffering = FALSE; - streamer->buffering_req.is_pre_buffering = FALSE; - if (streamer->buffering_percent == MAX_BUFFER_PERCENT) - streamer->is_buffering_done = FALSE; - else - streamer->buffering_percent = MAX_BUFFER_PERCENT; - } - else - { - /* need to update periodically in case of slink mode */ - if ((increased_per == TRUE) && - (buffer_percent%10 == 0) && - (streamer->buffering_req.mode == MM_PLAYER_BUFFERING_MODE_SLINK) && - (streamer->buffering_req.is_pre_buffering == FALSE)) - { - /* Update buffer setting to reflect data receiving rate for slink mode */ - streamer->need_update = TRUE; - } - } -} - -void __mm_player_streaming_buffering( mm_player_streaming_t* streamer, - GstMessage *buffering_msg, - guint64 content_size, - gint64 position, - gint64 duration) -{ - MMPLAYER_FENTER(); - - return_if_fail ( streamer ); - return_if_fail ( buffering_msg ); - return_if_fail ( GST_IS_MESSAGE ( buffering_msg ) ); - return_if_fail ( (GST_MESSAGE_TYPE ( buffering_msg ) == GST_MESSAGE_BUFFERING) ); - - if (buffering_msg) - { - if (position > (gint64)(streamer->buffering_req.initial_second * GST_SECOND)) - streamer->buffering_req.is_pre_buffering = FALSE; - - streaming_update_buffering_status(streamer, buffering_msg, position); - - if (!streamer->need_update) - { - //debug_log ("don't need to update buffering stats during buffering.\n"); - return; - } - - streamer->need_update = FALSE; - } - - streaming_update_buffer_setting (streamer, buffering_msg, content_size, position, duration); - - return; -} - diff --git a/src/mm_player_tracks.c b/src/mm_player_tracks.c deleted file mode 100644 index 3b19e8c..0000000 --- a/src/mm_player_tracks.c +++ /dev/null @@ -1,509 +0,0 @@ -/* - * libmm-player - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , naveen cherukuri , - * YeJin Cho , YoungHwan An - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -#include -#include -#include -#include "mm_player_utils.h" -#include "mm_player_tracks.h" - -/*--------------------------------------------------------------------------------------- -| LOCAL FUNCTION PROTOTYPES: | ----------------------------------------------------------------------------------------*/ -static int __mmplayer_track_get_language(mm_player_t* player, MMPlayerTrackType type, gint stream_index, gchar **code); - - -/*======================================================================================= -| FUNCTION DEFINITIONS | -=======================================================================================*/ -int _mmplayer_get_track_count(MMHandleType hplayer, MMPlayerTrackType type, int *count) -{ - mm_player_t* player = (mm_player_t*) hplayer; - MMHandleType attrs = 0; - int ret = MM_ERROR_NONE; - - MMPLAYER_FENTER(); - - /* check player handle */ - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(count, MM_ERROR_COMMON_INVALID_ARGUMENT); - return_val_if_fail((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED) - ||(MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING), - MM_ERROR_PLAYER_INVALID_STATE); - - attrs = MMPLAYER_GET_ATTRS(player); - if ( !attrs ) - { - debug_error("cannot get content attribute"); - return MM_ERROR_PLAYER_INTERNAL; - } - - switch (type) - { - case MM_PLAYER_TRACK_TYPE_AUDIO: - { - /*if function called for normal file [no multi audio] */ - if(player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) - { - *count = 0; - break; - } - ret = mm_attrs_get_int_by_name(attrs, "content_audio_track_num", count); - } - break; - case MM_PLAYER_TRACK_TYPE_TEXT: - ret = mm_attrs_get_int_by_name(attrs, "content_text_track_num", count); - break; - default: - ret = MM_ERROR_COMMON_INVALID_ARGUMENT; - break; - } - - debug_log ("%d track num : %d\n", type, *count); - - MMPLAYER_FLEAVE(); - - return ret; -} - -int _mmplayer_select_track(MMHandleType hplayer, MMPlayerTrackType type, int index) -{ - int ret = MM_ERROR_NONE; - mm_player_t* player = (mm_player_t*) hplayer; - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_FENTER(); - - - if (type == MM_PLAYER_TRACK_TYPE_TEXT && player->subtitle_language_list) - { - GstElement *subparse = NULL; - MMPlayerLangStruct *temp = NULL; - unsigned long cur_time = 0; - - if(!player->pipeline || !player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst) - { - ret = MM_ERROR_PLAYER_NOT_INITIALIZED; - goto EXIT; - } - - _mmplayer_get_position (hplayer, MM_PLAYER_POS_FORMAT_TIME, &cur_time); - temp = g_list_nth_data (player->subtitle_language_list, index); - - subparse = player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst; - debug_log("setting to language %s", temp->language_code); - g_object_set (G_OBJECT (subparse), "current-language", temp->language_key, NULL); - - _mmplayer_sync_subtitle_pipeline(player); - - } - else - { - ret = _mmplayer_change_track_language (hplayer, type, index); - } - -EXIT: - MMPLAYER_FLEAVE(); - return ret; -} - -#ifdef _MULTI_TRACK -int _mmplayer_track_add_subtitle_language(MMHandleType hplayer, int index) -{ - int ret = MM_ERROR_NONE; - mm_player_t* player = (mm_player_t*) hplayer; - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_FENTER(); - - if(!player->pipeline || !player->pipeline->mainbin[MMPLAYER_M_T_SUBMUX_EXTERNAL].gst) - { - ret = MM_ERROR_PLAYER_NOT_INITIALIZED; - goto EXIT; - } - - if (player->subtitle_language_list) - { - GstElement *subparse = NULL; - MMPlayerLangStruct *temp = NULL; - - temp = g_list_nth_data (player->subtitle_language_list, index); - temp->active = TRUE; - - subparse = player->pipeline->mainbin[MMPLAYER_M_T_SUBMUX_EXTERNAL].gst; - debug_log("adding to language %s", temp->language_code); - g_object_set (G_OBJECT (subparse), "current-language", temp->language_key, NULL); - g_object_set (G_OBJECT (subparse), "lang-list", player->subtitle_language_list, NULL); - - _mmplayer_sync_subtitle_pipeline(player); - } - else - { - debug_warning("It is for just subtitle track"); - ret = MM_ERROR_PLAYER_NO_OP; - goto EXIT; - } - -EXIT: - MMPLAYER_FLEAVE(); - return ret; -} - -int _mmplayer_track_remove_subtitle_language(MMHandleType hplayer, int index) -{ - int ret = MM_ERROR_NONE; - mm_player_t* player = (mm_player_t*) hplayer; - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_FENTER(); - - if(!player->pipeline || !player->pipeline->mainbin[MMPLAYER_M_T_SUBMUX_EXTERNAL].gst) - { - ret = MM_ERROR_PLAYER_NOT_INITIALIZED; - goto EXIT; - } - - if (player->subtitle_language_list) - { - GstElement *subparse = NULL; - MMPlayerLangStruct *temp = NULL; - - temp = g_list_nth_data (player->subtitle_language_list, index); - temp->active = FALSE; - - subparse = player->pipeline->mainbin[MMPLAYER_M_T_SUBMUX_EXTERNAL].gst; - debug_log("removing to language %s", temp->language_code); - g_object_set (G_OBJECT (subparse), "current-language", temp->language_key, NULL); - g_object_set (G_OBJECT (subparse), "lang-list", player->subtitle_language_list, NULL); - - _mmplayer_sync_subtitle_pipeline(player); - } - else - { - debug_warning("It is for just subtitle track"); - ret = MM_ERROR_PLAYER_NO_OP; - goto EXIT; - } - -EXIT: - MMPLAYER_FLEAVE(); - return ret; -} -#endif -int _mmplayer_get_current_track(MMHandleType hplayer, MMPlayerTrackType type, int *index) -{ - int ret = MM_ERROR_NONE; - mm_player_t* player = (mm_player_t*) hplayer; - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_FENTER(); - - if (type >= MM_PLAYER_TRACK_TYPE_MAX) - { - ret = MM_ERROR_INVALID_ARGUMENT; - debug_log("Not a proper type [type:%d] \n", type); - goto EXIT; - } - - if (type == MM_PLAYER_TRACK_TYPE_TEXT && player->subtitle_language_list) - { - GstElement *subparse = NULL; - int total_track_count = 0; - gchar* current_language = NULL; - MMPlayerLangStruct *temp = NULL; - MMHandleType attrs = 0; - - attrs = MMPLAYER_GET_ATTRS(player); - if (!attrs) - { - debug_error("cannot get content attribute"); - ret = MM_ERROR_PLAYER_INTERNAL; - goto EXIT; - } - - mm_attrs_get_int_by_name(attrs, "content_text_track_num", &total_track_count); - - subparse = player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst; - g_object_get (G_OBJECT (subparse), "current-language", ¤t_language, NULL); - debug_log("current language is %s ",current_language); - while (total_track_count) - { - temp = g_list_nth_data (player->subtitle_language_list, total_track_count - 1); - if (temp) - { - debug_log("find the list"); - if (!strcmp(temp->language_key, current_language)) - { - *index = total_track_count - 1; - debug_log("current lang index is %d", *index); - break; - } - } - total_track_count--; - } - } - else - { - if (player->selector[type].total_track_num <= 0) - { - ret = MM_ERROR_PLAYER_NO_OP; - debug_log("there is no track information [type:%d] \n", type); - goto EXIT; - } - - *index = player->selector[type].active_pad_index; - } - -EXIT: - MMPLAYER_FLEAVE(); - return ret; -} - -int _mmplayer_get_track_language_code(MMHandleType hplayer, MMPlayerTrackType type, int index, char **code) -{ - int ret = MM_ERROR_NONE; - - return_val_if_fail(hplayer, MM_ERROR_PLAYER_NOT_INITIALIZED); - mm_player_t* player = (mm_player_t*) hplayer; - MMPLAYER_FENTER(); - - if (type == MM_PLAYER_TRACK_TYPE_TEXT && player->subtitle_language_list) - { - int language_code_size = 3;/*Size of ISO-639-1*/ - MMPlayerLangStruct *language_list = NULL; - - *code = (char*)malloc(language_code_size * sizeof(char)); - if (*code == NULL) - { - ret = MM_ERROR_PLAYER_INTERNAL; - goto EXIT; - } - memset(*code, 0, language_code_size * sizeof(char)); - - language_list = g_list_nth_data (player->subtitle_language_list, index); - if (language_list == NULL) - { - debug_log ("%d is not a proper index \n", index); - goto EXIT; - } - strncpy(*code, language_list->language_code, language_code_size); - } - else - { - if (player->selector[type].total_track_num <= 0) - { - ret = MM_ERROR_PLAYER_NO_OP; - debug_log("language list is not available. [type:%d] \n", type); - goto EXIT; - } - - if(index < 0 || index >= player->selector[type].total_track_num) - { - ret = MM_ERROR_INVALID_ARGUMENT; - debug_log("Not a proper index : %d \n", index); - goto EXIT; - } - - ret = __mmplayer_track_get_language(player, type, index, code); - } - -EXIT: - MMPLAYER_FLEAVE(); - return ret; -} - -void _mmplayer_track_initialize(mm_player_t* player) -{ - MMPlayerTrackType type = MM_PLAYER_TRACK_TYPE_AUDIO; - - MMPLAYER_FENTER(); - - for (;typeselector[type].total_track_num = 0; - player->selector[type].channels = g_ptr_array_new(); - } -} - -void _mmplayer_track_destroy(mm_player_t* player) -{ - MMPlayerTrackType type = MM_PLAYER_TRACK_TYPE_AUDIO; - MMHandleType attrs = 0; - MMPLAYER_FENTER(); - - attrs = MMPLAYER_GET_ATTRS(player); - if (attrs) - { - mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 0); - mm_attrs_set_int_by_name(attrs, "content_video_track_num", 0); - mm_attrs_set_int_by_name(attrs, "content_text_track_num", 0); - - if (mmf_attrs_commit (attrs)) - debug_error("failed to commit.\n"); - } - - for (;typeselector[type].active_pad_index = 0; - player->selector[type].total_track_num = 0; - - if (player->selector[type].channels) - g_ptr_array_free (player->selector[type].channels, TRUE); - player->selector[type].channels = NULL; - } -} - -void _mmplayer_track_update_info(mm_player_t* player, MMPlayerTrackType type, GstPad *sinkpad) -{ - MMPLAYER_FENTER(); - - player->selector[type].total_track_num++; - g_ptr_array_add (player->selector[type].channels, sinkpad); - - debug_log ("type:%d, total track:%d\n", type, player->selector[type].total_track_num); -} - -static int __mmplayer_track_get_language(mm_player_t* player, MMPlayerTrackType type, gint stream_index, gchar **code) -{ - int ret = MM_ERROR_NONE; - - GstTagList *tag_list = NULL; - gchar* tag = NULL; - GstPad *sinkpad = NULL; - gint language_code_size = 3; /*Size of ISO-639-1*/ - - MMPLAYER_FENTER(); - - *code = (char *)malloc(language_code_size*sizeof(char)); - if(*code == NULL) - { - ret = MM_ERROR_PLAYER_INTERNAL; - goto EXIT; - } - memset(*code,0,language_code_size*sizeof(char)); - - debug_log ("total track num : %d , req idx : %d\n", player->selector[type].total_track_num, stream_index); - - if (stream_index < player->selector[type].total_track_num) - { - sinkpad = g_ptr_array_index (player->selector[type].channels, stream_index); - } - else - { - ret = MM_ERROR_INVALID_ARGUMENT; - goto EXIT; - } - - g_object_get (sinkpad, "tags", &tag_list, NULL); - //secure_debug_log ("[%s]\n", gst_tag_list_to_string(tag_list)); - - gst_tag_list_get_string (tag_list, GST_TAG_LANGUAGE_CODE, &tag); - - if(!tag) - { - debug_log("there is no lang info - und\n"); - strncpy(*code, "und", language_code_size); - } - else - { - debug_log("language information[%d] code: %s, len: %d \n", type, tag, strlen(tag)); - strncpy(*code, tag, /*strlen(tag)*/language_code_size); - g_free (tag); - } - - if (tag_list) - gst_tag_list_free (tag_list); - -EXIT: - MMPLAYER_FLEAVE(); - return ret; -} -#ifdef _MULTI_TRACK -int _mmplayer_track_foreach_selected_subtitle_language(MMHandleType hplayer,_mmplayer_track_selected_subtitle_language_cb foreach_cb, void *user_data) -{ - int ret = MM_ERROR_NONE; - mm_player_t* player = (mm_player_t*) hplayer; - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_FENTER(); - - int index = -1; - - if (player->subtitle_language_list) - { - int total_track_count = 0; - MMPlayerLangStruct *temp = NULL; - MMHandleType attrs = 0; - - attrs = MMPLAYER_GET_ATTRS(player); - if (!attrs) - { - debug_error("cannot get content attribute"); - ret = MM_ERROR_PLAYER_INTERNAL; - goto EXIT; - } - mm_attrs_get_int_by_name(attrs, "content_text_track_num", &total_track_count); - - if(!total_track_count) - { - debug_warning("There are no subtitle track selected."); - ret = MM_ERROR_PLAYER_NO_OP; - goto EXIT; - } - - while (total_track_count) - { - temp = g_list_nth_data (player->subtitle_language_list, total_track_count - 1); - if (temp) - { - debug_log("find the list"); - if (temp->active) - { - index = total_track_count - 1; - debug_log("active subtitle track index is %d", index); - if (!foreach_cb(index, user_data)) - { - ret = MM_ERROR_PLAYER_INTERNAL; - goto CALLBACK_ERROR; - } - } - } - total_track_count--; - } - - debug_log("we will return -1 for notifying the end to user"); - - /* After returning all selected indexs, we will return -1 for notifying the end to user */ - if (!foreach_cb(-1, user_data)) - { - ret = MM_ERROR_PLAYER_INTERNAL; - goto CALLBACK_ERROR; - } - } - -CALLBACK_ERROR: - debug_error("foreach callback returned error"); - -EXIT: - MMPLAYER_FLEAVE(); - return ret; - - -} -#endif diff --git a/src/mm_player_utils.c b/src/mm_player_utils.c deleted file mode 100755 index 937c91f..0000000 --- a/src/mm_player_utils.c +++ /dev/null @@ -1,518 +0,0 @@ -/* - * libmm-player - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , YeJin Cho , - * Seungbae Shin , YoungHwan An - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "mm_player_utils.h" - -/* for getting status of connecting external display */ -#include -#include -#include - -int util_exist_file_path(const char *file_path) -{ - int fd = 0; - struct stat stat_results = {0, }; - - if (!file_path || !strlen(file_path)) - return MM_ERROR_PLAYER_FILE_NOT_FOUND; - - fd = open (file_path, O_RDONLY); - - if (fd < 0) - { - debug_error("failed to open file by %s (%d)", strerror(errno), errno); - - if (EACCES == errno) - return MM_ERROR_PLAYER_PERMISSION_DENIED; - - return MM_ERROR_PLAYER_FILE_NOT_FOUND; - } - - if (fstat(fd, &stat_results) < 0) - { - debug_error("failed to get file status"); - } - else if (stat_results.st_size == 0) - { - debug_error("file size is zero"); - close(fd); - return MM_ERROR_PLAYER_FILE_NOT_FOUND; - } - else - { - debug_warning("file size : %lld bytes", (long long)stat_results.st_size); - } - - close(fd); - - return MM_ERROR_NONE; -} - -bool util_write_file_backup(const char *backup_path, char *data_ptr, int data_size) -{ - FILE *fp = NULL; - int wsize = 0; - - fp = fopen(backup_path, "wb"); - if (!fp) - return FALSE; - - wsize = fwrite(data_ptr, sizeof(char), data_size, fp); - - fclose(fp); - - if (wsize != data_size) { - if (!access(backup_path, R_OK)) - remove(backup_path); - - debug_error("No space to write!\n"); - - return FALSE; - } - - return TRUE; -} - -bool util_remove_file_backup(const char *backup_path) -{ - if (!backup_path || !strlen(backup_path)) - return FALSE; - - int res = access(backup_path, R_OK); - if (!res) - { - if (remove(backup_path) == -1) - return FALSE; - } - - return TRUE; -} - -#define DETECTION_PREFIX_SIZE 20 -//bool util_is_midi_type_by_mem(void *mem, int size) -int util_is_midi_type_by_mem(void *mem, int size) -{ - const char *p = (const char *)mem; - - if (size < DETECTION_PREFIX_SIZE) - return MM_AUDIO_CODEC_INVALID; - - /* mmf file detection */ - if (p[0] == 'M' && p[1] == 'M' && p[2] == 'M' && p[3] == 'D') { - debug_log("MM_AUDIO_CODEC_MMF\n"); - return MM_AUDIO_CODEC_MMF; - } - - /* midi file detection */ - if (p[0] == 'M' && p[1] == 'T' && p[2] == 'h' && p[3] == 'd') { - debug_log ("MM_AUDIO_CODEC_MIDI, %d\n", MM_AUDIO_CODEC_MIDI); - return MM_AUDIO_CODEC_MIDI; - } - /* mxmf file detection */ - if (p[0] == 'X' && p[1] == 'M' && p[2] == 'F' && p[3] == '_') { - debug_log ("MM_AUDIO_CODEC_MXMF\n"); - return MM_AUDIO_CODEC_MXMF; - } - - /* wave file detection */ - if (p[0] == 'R' && p[1] == 'I' && p[2] == 'F' && p[3] == 'F' && - p[8] == 'W' && p[9] == 'A' && p[10] == 'V' && p[11] == 'E' && - p[12] == 'f' && p[13] == 'm' && p[14] == 't') { - debug_log ("MM_AUDIO_CODEC_WAVE\n"); - return MM_AUDIO_CODEC_WAVE; - } - /* i-melody file detection */ - if (memcmp(p, "BEGIN:IMELODY", 13) == 0) - { - debug_log ("MM_AUDIO_CODEC_IMELODY\n"); - return MM_AUDIO_CODEC_IMELODY; - } - - return MM_AUDIO_CODEC_INVALID; -} - -//bool util_is_midi_type_by_file(const char *file_path) -int util_is_midi_type_by_file(const char *file_path) -{ - struct stat file_attrib; - FILE *fp = NULL; - char prefix[DETECTION_PREFIX_SIZE] = {0,}; - int size; - - if (!file_path) - return FALSE; - - fp = fopen(file_path, "r"); - - if (!fp) - return FALSE; - - memset(&file_attrib, 0, sizeof(file_attrib)); - - if (stat(file_path, &file_attrib) != 0) - { - fclose(fp); - return FALSE; - } - - size = (int) file_attrib.st_size; - - if (size < DETECTION_PREFIX_SIZE) - { - fclose(fp); - return FALSE; - } - - size = fread(prefix, sizeof(char), DETECTION_PREFIX_SIZE, fp); - - fclose(fp); - - return util_is_midi_type_by_mem(prefix, size); -} - -char** -util_get_cookie_list ( const char *cookies ) -{ - char **cookie_list = NULL; - char *temp = NULL; - gint i = 0; - - if ( !cookies || !strlen(cookies) ) - return NULL; - - secure_debug_log("cookies : %d[bytes] - %s \n", strlen(cookies), cookies); - - temp = g_strdup(cookies); - - /* trimming. it works inplace */ - g_strstrip(temp); - - /* split */ - cookie_list = g_strsplit(temp, ";", 100); - - for ( i = 0; i < g_strv_length(cookie_list); i++ ) - { - if ( cookie_list[i] && strlen(cookie_list[i]) ) - { - g_strstrip(cookie_list[i]); - secure_debug_log("cookie_list[%d] : %d[bytes] - %s \n", i, strlen(cookie_list[i]), cookie_list[i]); - } - else - { - cookie_list[i][0]='\0'; - } - } - - if (temp) - g_free (temp); - temp=NULL; - - return cookie_list; -} - -bool util_check_valid_url ( const char *proxy ) -{ - struct in_addr proxy_addr; - bool ret = TRUE; - - return_val_if_fail ( proxy, FALSE ); - return_val_if_fail ( strlen(proxy), FALSE ); - - if ( inet_aton(proxy, &proxy_addr) != 0 ) - { - debug_warning("invalid proxy is set. \n"); - ret = FALSE; - } - - return ret; -} - -/* check the given path is indicating sdp file */ -bool -util_is_sdp_file ( const char *path ) -{ - gboolean ret = FALSE; - gchar* uri = NULL; - - MMPLAYER_FENTER(); - - return_val_if_fail ( path, FALSE ); - - uri = g_ascii_strdown ( path, -1 ); - - if ( uri == NULL) - { - return FALSE; - } - - /* trimming */ - g_strstrip( uri ); - - /* strlen(".sdp") == 4 */ - if ( strlen( uri ) <= 4 ) - { - debug_warning ( "path is too short.\n" ); - return ret; - } - - /* first, check extension name */ - ret = g_str_has_suffix ( uri, "sdp" ); - - /* second, if no suffix is there, check it's contents */ - if ( ! ret ) - { - /* FIXIT : do it soon */ - } - - g_free( uri); - uri = NULL; - - return ret; -} - -int64_t -util_get_time ( void ) -{ - struct timeval tv; - gettimeofday(&tv,NULL); - return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec; -} - -int -util_get_rank_increase ( const char *factory_class ) -{ - gint rank_pri_inc = 20; - gint rank_sec_inc = 10; - gint ret = 0; - - if ( g_strrstr(factory_class,"Dsp") ) - ret = rank_pri_inc; - else if ( g_strrstr(factory_class,"HW") ) - ret = rank_pri_inc; - else if ( g_strrstr(factory_class,"Arm") ) - ret = rank_sec_inc; - - return ret; -} - -int -util_factory_rank_compare(GstPluginFeature *f1, GstPluginFeature *f2) // @ -{ - const gchar *klass; - int f1_rank_inc=0, f2_rank_inc=0; - - klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(f1)); - f1_rank_inc = util_get_rank_increase ( klass ); - - klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(f2)); - f2_rank_inc = util_get_rank_increase ( klass ); - - return (gst_plugin_feature_get_rank(f2)+f2_rank_inc) - (gst_plugin_feature_get_rank(f1)+f1_rank_inc ); -} - -const char* -util_get_charset(const char *file_path) -{ - UCharsetDetector* ucsd; - const UCharsetMatch* ucm; - UErrorCode status = U_ZERO_ERROR; - - const char* charset = NULL; - char *buf = NULL; - FILE* fin =0; - size_t n_size = 0; - - fin = fopen(file_path, "r"); - if (!fin) - { - secure_debug_error("fail to open file %s\n", file_path); - return NULL; - } - - ucsd = ucsdet_open( &status ); - if( U_FAILURE(status) ) { - debug_error("fail to ucsdet_open\n"); - goto done; - } - - ucsdet_enableInputFilter( ucsd, TRUE ); - - buf = g_malloc(1024*1024); - if (!buf) - { - debug_error("fail to alloc\n"); - goto done; - } - - n_size = fread( buf, 1, 1024*1024, fin ); - - if (!n_size) - goto done; - - ucsdet_setText( ucsd, buf, strlen(buf), &status ); - if( U_FAILURE(status) ) { - debug_error("fail to ucsdet_setText\n"); - goto done; - } - - ucm = ucsdet_detect( ucsd, &status ); - if( U_FAILURE(status) ) { - debug_error("fail to ucsdet_detect\n"); - goto done; - } - - charset = ucsdet_getName( ucm, &status ); - if( U_FAILURE(status) ) { - debug_error("fail to ucsdet_getName\n"); - goto done; - } - -done: - if(fin) - fclose(fin); - - if(ucsd) - ucsdet_close( ucsd ); - - if (buf) - g_free(buf); - - return charset; -} - -int -util_get_is_connected_external_display(void) -{ - int is_connected_hdmi = -1; - int is_connected_mirroring = -1; - -#if 0 - if (vconf_get_int(VCONFKEY_SYSMAN_HDMI, &is_connected_hdmi)) - debug_error("[hdmi]vconf_set_int FAIL"); - if (vconf_get_int(VCONFKEY_SCREEN_MIRRORING_STATE, &is_connected_mirroring)) - debug_error("[mirroring]vconf_set_int FAIL"); - - /* if conneted with external display */ - if (is_connected_mirroring == VCONFKEY_SCREEN_MIRRORING_CONNECTED) { - debug_warning ("connected with mirroring display"); - return MMPLAYER_DISPLAY_MIRRORING_ACTIVE; - } - if (is_connected_hdmi == VCONFKEY_SYSMAN_HDMI_CONNECTED) { - debug_warning ("connected with external display"); - return MMPLAYER_DISPLAY_HDMI_ACTIVE; - } - if ((is_connected_mirroring == VCONFKEY_SCREEN_MIRRORING_ACTIVATED || is_connected_mirroring == VCONFKEY_SCREEN_MIRRORING_DEACTIVATED) && is_connected_hdmi == VCONFKEY_SYSMAN_HDMI_DISCONNECTED) { - debug_warning ("non-connected status"); - return MMPLAYER_DISPLAY_NULL; - } -#endif - debug_error ("it is not registered (%d, %d)", is_connected_mirroring, is_connected_hdmi); - return -1; -} - -int util_get_pixtype(unsigned int fourcc) -{ - int pixtype = MM_PIXEL_FORMAT_INVALID; - - /* - char *pfourcc = (char*)&fourcc; - - debug_log("fourcc(%c%c%c%c)", - pfourcc[0], pfourcc[1], pfourcc[2], pfourcc[3]); - */ - - - switch (fourcc) { - case GST_MAKE_FOURCC ('S', 'N', '1', '2'): - case GST_MAKE_FOURCC ('N', 'V', '1', '2'): - pixtype = MM_PIXEL_FORMAT_NV12; - break; - case GST_MAKE_FOURCC ('S', 'T', '1', '2'): - pixtype = MM_PIXEL_FORMAT_NV12T; - break; - case GST_MAKE_FOURCC ('S', 'N', '2', '1'): - case GST_MAKE_FOURCC ('N', 'V', '2', '1'): - pixtype = MM_PIXEL_FORMAT_NV21; - break; - case GST_MAKE_FOURCC ('S', 'U', 'Y', 'V'): - case GST_MAKE_FOURCC ('Y', 'U', 'Y', 'V'): - case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'): - pixtype = MM_PIXEL_FORMAT_YUYV; - break; - case GST_MAKE_FOURCC ('S', 'Y', 'V', 'Y'): - case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'): - pixtype = MM_PIXEL_FORMAT_UYVY; - break; - case GST_MAKE_FOURCC ('S', '4', '2', '0'): - case GST_MAKE_FOURCC ('I', '4', '2', '0'): - pixtype = MM_PIXEL_FORMAT_I420; - break; - case GST_MAKE_FOURCC ('Y', 'V', '1', '2'): - pixtype = MM_PIXEL_FORMAT_YV12; - break; - case GST_MAKE_FOURCC ('4', '2', '2', 'P'): - pixtype = MM_PIXEL_FORMAT_422P; - break; - case GST_MAKE_FOURCC ('R', 'G', 'B', 'P'): - pixtype = MM_PIXEL_FORMAT_RGB565; - break; - case GST_MAKE_FOURCC ('R', 'G', 'B', '3'): - pixtype = MM_PIXEL_FORMAT_RGB888; - break; - case GST_MAKE_FOURCC ('A', 'R', 'G', 'B'): - case GST_MAKE_FOURCC ('x', 'R', 'G', 'B'): - pixtype = MM_PIXEL_FORMAT_ARGB; - break; - case GST_MAKE_FOURCC ('B', 'G', 'R', 'A'): - case GST_MAKE_FOURCC ('B', 'G', 'R', 'x'): - case GST_MAKE_FOURCC ('S', 'R', '3', '2'): - pixtype = MM_PIXEL_FORMAT_RGBA; - break; - case GST_MAKE_FOURCC ('J', 'P', 'E', 'G'): - case GST_MAKE_FOURCC ('P', 'N', 'G', ' '): - pixtype = MM_PIXEL_FORMAT_ENCODED; - break; - /*FIXME*/ - case GST_MAKE_FOURCC ('I', 'T', 'L', 'V'): - pixtype = MM_PIXEL_FORMAT_ITLV_JPEG_UYVY; - break; - default: - debug_error("Not supported fourcc type(%c%c%c%c)", - fourcc, fourcc>>8, fourcc>>16, fourcc>>24); - pixtype = MM_PIXEL_FORMAT_INVALID; - break; - } - - return pixtype; -} diff --git a/src/mused/mm_player_mused.c b/src/mused/mm_player_mused.c deleted file mode 100644 index 9a218e7..0000000 --- a/src/mused/mm_player_mused.c +++ /dev/null @@ -1,914 +0,0 @@ -/* - * libmm-player - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: YoungHwan An - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/*=========================================================================================== -| | -| INCLUDE FILES | -| | -========================================================================================== */ -#include -#include -#include -#include -#ifdef HAVE_WAYLAND -#include -#endif -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "mm_player_priv.h" -#include "mm_player_ini.h" -#include "mm_player_attrs.h" -#include "mm_player_utils.h" -#include - -/*=========================================================================================== -| | -| LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE | -| | -========================================================================================== */ - -/*--------------------------------------------------------------------------- -| GLOBAL CONSTANT DEFINITIONS: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| IMPORTED VARIABLE DECLARATIONS: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| IMPORTED FUNCTION DECLARATIONS: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| LOCAL #defines: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| LOCAL CONSTANT DEFINITIONS: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| LOCAL DATA TYPE DEFINITIONS: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| GLOBAL VARIABLE DEFINITIONS: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| LOCAL VARIABLE DEFINITIONS: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| LOCAL FUNCTION PROTOTYPES: | ----------------------------------------------------------------------------*/ -static gboolean _mmplayer_mused_init_gst(mm_player_t* player); -static int _mmplayer_mused_realize(mm_player_t *player, char *string_caps); -static int _mmplayer_mused_unrealize(mm_player_t *player); -static MMHandleType _mmplayer_mused_construct_attribute(mm_player_t *player); -static int _mmplayer_mused_update_video_param(mm_player_t *player); -static int _mmplayer_get_raw_video_caps(mm_player_t *player, char **caps); -static int __mmplayer_mused_gst_destroy_pipeline(mm_player_t *player); -static int _mmplayer_mused_gst_pause(mm_player_t *player); -static int _mmplayer_set_shm_stream_path(MMHandleType hplayer, const char *path); -/*=========================================================================================== -| | -| FUNCTION DEFINITIONS | -| | -========================================================================================== */ - -int mm_player_mused_create(MMHandleType *player) -{ - int result = MM_ERROR_NONE; - mm_player_t* new_player = NULL; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - /* alloc player structure */ - new_player = g_malloc0(sizeof(mm_player_t)); - if ( ! new_player ) - { - debug_error("Cannot allocate memory for player\n"); - goto ERROR; - } - - /* create player lock */ - g_mutex_init(&new_player->cmd_lock); - - /* load ini files */ - result = mm_player_ini_load(&new_player->ini); - if(result != MM_ERROR_NONE) - { - debug_error("can't load ini"); - goto ERROR; - } - - /* initialize player state */ - MMPLAYER_CURRENT_STATE(new_player) = MM_PLAYER_STATE_NONE; - MMPLAYER_PREV_STATE(new_player) = MM_PLAYER_STATE_NONE; - MMPLAYER_PENDING_STATE(new_player) = MM_PLAYER_STATE_NONE; - MMPLAYER_TARGET_STATE(new_player) = MM_PLAYER_STATE_NONE; - - /* check current state */ - if (__mmplayer_check_state ( new_player, MMPLAYER_COMMAND_CREATE ) - != MM_ERROR_NONE) - goto ERROR; - - /* construct attributes */ - new_player->attrs = _mmplayer_mused_construct_attribute(new_player); - - if ( !new_player->attrs ) - { - debug_error("Failed to construct attributes\n"); - goto ERROR; - } - - /* initialize gstreamer with configured parameter */ - if ( ! _mmplayer_mused_init_gst(new_player) ) - { - debug_error("Initializing gstreamer failed\n"); - goto ERROR; - } - MMPLAYER_SET_STATE ( new_player, MM_PLAYER_STATE_NULL ); - MMPLAYER_STATE_CHANGE_TIMEOUT(new_player) = new_player->ini.localplayback_state_change_timeout; - - *player = (MMHandleType)new_player; - return result; -ERROR: - if( new_player ) { - g_mutex_clear(&new_player->cmd_lock); - _mmplayer_deconstruct_attribute(new_player); - g_free( new_player ); - } - - *player = NULL; - return MM_ERROR_PLAYER_NO_FREE_SPACE; -} - -static gboolean -_mmplayer_mused_init_gst(mm_player_t *player) -{ - static gboolean initialized = FALSE; - static const int max_argc = 50; - gint* argc = NULL; - gchar** argv = NULL; - gchar** argv2 = NULL; - GError *err = NULL; - int i = 0; - int arg_count = 0; - - if ( initialized ) - { - debug_log("gstreamer already initialized.\n"); - return TRUE; - } - - /* alloc */ - argc = malloc( sizeof(int) ); - argv = malloc( sizeof(gchar*) * max_argc ); - argv2 = malloc( sizeof(gchar*) * max_argc ); - - if ( !argc || !argv || !argv2) - goto GST_INIT_EXIT; - - memset( argv, 0, sizeof(gchar*) * max_argc ); - memset( argv2, 0, sizeof(gchar*) * max_argc ); - - /* add initial */ - *argc = 1; - argv[0] = g_strdup( "mmplayer_mused" ); - - /* we would not do fork for scanning plugins */ - argv[*argc] = g_strdup("--gst-disable-registry-fork"); - (*argc)++; - - arg_count = *argc; - - for ( i = 0; i < arg_count; i++ ) - argv2[i] = argv[i]; - - /* initializing gstreamer */ - if ( ! gst_init_check (argc, &argv, &err)) - { - debug_error("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred"); - if (err) - { - g_error_free (err); - } - } - - initialized = TRUE; -GST_INIT_EXIT: - /* release */ - for ( i = 0; i < arg_count; i++ ) - { - MMPLAYER_FREEIF( argv2[i] ); - } - - MMPLAYER_FREEIF( argv ); - MMPLAYER_FREEIF( argv2 ); - MMPLAYER_FREEIF( argc ); - - return initialized; -} - -int mm_player_mused_destroy(MMHandleType player) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - /* destroy can called at anytime */ - MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_DESTROY ); - - __mmplayer_mused_gst_destroy_pipeline(player); - - /* release attributes */ - if( !_mmplayer_deconstruct_attribute( player ) ) { - debug_error("failed to deconstruct attribute"); - result = MM_ERROR_PLAYER_INTERNAL; - } - - MMPLAYER_CMD_UNLOCK( player ); - - g_mutex_clear(&((mm_player_t*)player)->cmd_lock); - g_free( player ); - return result; -} - - -int mm_player_mused_realize(MMHandleType player, char *caps) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_mused_realize((mm_player_t *)player, caps); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -static int _mmplayer_mused_realize(mm_player_t *player, char *string_caps) -{ - int result = MM_ERROR_NONE; - GstElement *src; - GstElement *sink; - GstBus *bus; - GstCaps *caps; - MMPlayerGstElement *mainbin = NULL; - MMHandleType attrs = MMPLAYER_GET_ATTRS(player); - int width = 0; - int height = 0; - gboolean link; - char *stream_path = NULL; - int attr_ret; - int surface_type = 0; - gchar *videosink_element = NULL; - gchar *videosrc_element = NULL; - - /* check current state */ - MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_REALIZE ); - - /* create pipeline handles */ - if ( player->pipeline ) - { - debug_warning("pipeline should be released before create new one\n"); - return result; - } - /* alloc handles */ - player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0( sizeof(MMPlayerGstPipelineInfo) ); - if (player->pipeline == NULL) - return MM_ERROR_PLAYER_NO_FREE_SPACE; - - /* create mainbin */ - mainbin = (MMPlayerGstElement*) g_malloc0( sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM ); - if (!mainbin) { - result = MM_ERROR_OUT_OF_MEMORY; - goto REALIZE_ERROR; - } - - /* create pipeline */ - mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE; - mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("playerClient"); - debug_log("gst new %p", mainbin[MMPLAYER_M_PIPE].gst); - if ( ! mainbin[MMPLAYER_M_PIPE].gst ) - { - debug_error("failed to create pipeline\n"); - result = MM_ERROR_PLAYER_INTERNAL; - goto REALIZE_ERROR; - } - - if (strlen(player->ini.videosrc_element_remote) > 0) - videosrc_element = player->ini.videosrc_element_remote; - else { - debug_error("fail to find source element"); - result = MM_ERROR_PLAYER_INTERNAL; - goto REALIZE_ERROR; - } - - /* create source */ - src = gst_element_factory_make(videosrc_element, videosrc_element); - if ( !src ) { - debug_error("faile to create %s", videosrc_element); - result = MM_ERROR_PLAYER_INTERNAL; - goto REALIZE_ERROR; - } - if(strcmp(videosrc_element, "shmsrc") == 0) { - attr_ret = mm_attrs_get_string_by_name ( attrs, "shm_stream_path", &stream_path ); - if(attr_ret == MM_ERROR_NONE && stream_path) { - LOGD("stream path : %s", stream_path); - g_object_set(G_OBJECT(src), - "socket-path", stream_path, - "is-live", TRUE, - NULL); - } else { - result = MM_ERROR_PLAYER_INTERNAL; - goto REALIZE_ERROR; - } - } - - mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC; - mainbin[MMPLAYER_M_SRC].gst = src; - - /* create sink */ - mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type); - switch(surface_type) - { - case MM_DISPLAY_SURFACE_X: - if (strlen(player->ini.videosink_element_x) > 0) - videosink_element = player->ini.videosink_element_x; - else { - result = MM_ERROR_PLAYER_NOT_INITIALIZED; - goto REALIZE_ERROR; - } - break; - default: - debug_error("Not support surface type %d", surface_type); - result = MM_ERROR_INVALID_ARGUMENT; - goto REALIZE_ERROR; - } - sink = gst_element_factory_make(videosink_element, videosink_element); - if ( !src ) { - debug_error("faile to create %s", videosink_element); - result = MM_ERROR_PLAYER_INTERNAL; - goto REALIZE_ERROR; - } - mainbin[MMPLAYER_M_V_SINK].id = MMPLAYER_M_V_SINK; - mainbin[MMPLAYER_M_V_SINK].gst = sink; - - /* now we have completed mainbin. take it */ - player->pipeline->mainbin = mainbin; - - result = _mmplayer_mused_update_video_param(player); - if(result != MM_ERROR_NONE) - goto REALIZE_ERROR; - - /* add and link */ - gst_bin_add_many(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), - mainbin[MMPLAYER_M_SRC].gst, - mainbin[MMPLAYER_M_V_SINK].gst, - NULL); - - mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &width); - mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &height); - - caps = gst_caps_from_string(string_caps); - - link = gst_element_link_filtered(mainbin[MMPLAYER_M_SRC].gst, mainbin[MMPLAYER_M_V_SINK].gst, caps); - gst_caps_unref(caps); - if(!link) { - debug_error("element link error"); - result = MM_ERROR_PLAYER_INTERNAL; - goto REALIZE_ERROR; - } - - /* connect bus callback */ - bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst)); - if ( !bus ) { - debug_error ("cannot get bus from pipeline.\n"); - result = MM_ERROR_PLAYER_INTERNAL; - goto REALIZE_ERROR; - } - - player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player); - - player->context.thread_default = g_main_context_get_thread_default(); - - if (NULL == player->context.thread_default) - { - player->context.thread_default = g_main_context_default(); - debug_log("thread-default context is the global default context"); - } - debug_log("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher); - - /* set sync handler to get tag synchronously */ - gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL); - - gst_object_unref(GST_OBJECT(bus)); - - /* warm up */ - if ( GST_STATE_CHANGE_FAILURE == - gst_element_set_state(mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY ) ) { - debug_error("failed to set state(READY) to pipeline"); - result = MM_ERROR_PLAYER_INVALID_STATE; - goto REALIZE_ERROR; - } - /* run */ - if (GST_STATE_CHANGE_FAILURE == - gst_element_set_state (mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED)) { - debug_error("failed to set state(PAUSE) to pipeline"); - result = MM_ERROR_PLAYER_INVALID_STATE; - goto REALIZE_ERROR; - } - if (GST_STATE_CHANGE_FAILURE == - gst_element_set_state (mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING)) { - debug_error("failed to set state(PLAYING) to pipeline"); - result = MM_ERROR_PLAYER_INVALID_STATE; - goto REALIZE_ERROR; - } - - MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_READY ); - return result; - -REALIZE_ERROR: - __mmplayer_mused_gst_destroy_pipeline(player); - return result; -} - -static int _mmplayer_mused_update_video_param(mm_player_t *player) -{ - MMHandleType attrs = 0; - int surface_type = 0; - MMPlayerGstElement* mainbin = player->pipeline->mainbin; - - if( !mainbin ) { - debug_error("mainbin was not created"); - return MM_ERROR_PLAYER_INTERNAL; - } - attrs = MMPLAYER_GET_ATTRS(player); - if ( !attrs ) { - debug_error("cannot get content attribute"); - return MM_ERROR_PLAYER_INTERNAL; - } - /* update display surface */ - mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type); - debug_log("check display surface type attribute: %d", surface_type); - - /* configuring display */ - switch ( surface_type ) - { - case MM_DISPLAY_SURFACE_X: - { - /* ximagesink or xvimagesink */ - void *surface = NULL; - -#ifdef HAVE_WAYLAND - /*set wl_display*/ - void* wl_display = NULL; - GstContext *context = NULL; - int wl_window_x = 0; - int wl_window_y = 0; - int wl_window_width = 0; - int wl_window_height = 0; - - mm_attrs_get_data_by_name(attrs, "wl_display", &wl_display); - if (wl_display) - context = gst_wayland_display_handle_context_new(wl_display); - if (context) - gst_element_set_context(GST_ELEMENT(mainbin[MMPLAYER_M_V_SINK].gst), context); - - /*It should be set after setting window*/ - mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x); - mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y); - mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width); - mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height); -#endif - mm_attrs_get_data_by_name(attrs, "display_overlay", &surface); - if ( surface ) { -#ifdef HAVE_WAYLAND - guintptr wl_surface = (guintptr)surface; - debug_log("set video param : surface %p", wl_surface); - gst_video_overlay_set_window_handle( - GST_VIDEO_OVERLAY( mainbin[MMPLAYER_M_V_SINK].gst ), - wl_surface ); - /* After setting window handle, set render rectangle */ - gst_video_overlay_set_render_rectangle( - GST_VIDEO_OVERLAY( mainbin[MMPLAYER_M_V_SINK].gst ), - wl_window_x,wl_window_y,wl_window_width,wl_window_height); -#else - int xwin_id = 0; - xwin_id = *(int*)surface; - debug_log("set video param : xid %d", xwin_id); - if (xwin_id) - { - gst_video_overlay_set_window_handle( - GST_VIDEO_OVERLAY( player->pipeline->videobin[MMPLAYER_V_SINK].gst ), - xwin_id ); - } -#endif - } - else - debug_warning("still we don't have surface on player attribute. create it's own surface."); - } - break; - default: - debug_log("Noting to update"); - break; - } - - return MM_ERROR_NONE; -} - -int mm_player_mused_unrealize(MMHandleType player) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_mused_unrealize(player); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -static int _mmplayer_mused_unrealize(mm_player_t *player) -{ - int ret = MM_ERROR_NONE; - - /* check current state */ - MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_UNREALIZE ); - - ret = __mmplayer_mused_gst_destroy_pipeline(player); - - MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_NULL ); - - return ret; -} - -static int __mmplayer_mused_gst_destroy_pipeline(mm_player_t *player) -{ - int ret = MM_ERROR_NONE; - /* cleanup gst stuffs */ - if ( player->pipeline ) { - MMPlayerGstElement* mainbin = player->pipeline->mainbin; - - /* disconnecting bus watch */ - if ( player->bus_watcher ) - __mmplayer_remove_g_source_from_context( - player->context.thread_default, player->bus_watcher); - player->bus_watcher = 0; - - if ( mainbin ) { - gint timeout; - GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (mainbin[MMPLAYER_M_PIPE].gst)); - gst_bus_set_sync_handler (bus, NULL, NULL, NULL); - gst_object_unref(bus); - - timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player); - ret = __mmplayer_gst_set_state ( player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout ); - if ( ret != MM_ERROR_NONE ) { - debug_error("fail to change state to NULL\n"); - return MM_ERROR_PLAYER_INTERNAL; - } - debug_log("succeeded in chaning state to NULL\n"); - - debug_log("gst unref %p", mainbin[MMPLAYER_M_PIPE].gst); - gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst)); - - debug_log("free mainbin"); - MMPLAYER_FREEIF( player->pipeline->mainbin ); - } - debug_log("free pipelin"); - MMPLAYER_FREEIF( player->pipeline ); - } - debug_log("finished destroy pipeline"); - - return ret; -} - -static int _mmplayer_mused_gst_pause(mm_player_t *player) -{ - /* check current state */ - MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_UNREALIZE ); - - int ret = MM_ERROR_NONE; - if ( player->pipeline ) { - MMPlayerGstElement* mainbin = player->pipeline->mainbin; - - if ( mainbin ) { - gint timeout; - - timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player); - ret = __mmplayer_gst_set_state ( player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout ); - if ( ret != MM_ERROR_NONE ) { - debug_error("fail to change state to PAUSED"); - return MM_ERROR_PLAYER_INTERNAL; - } - debug_log("succeeded in chaning state to PAUSED"); - MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PAUSED ); - } - } - - return MM_ERROR_NONE; -} - -int mm_player_mused_pre_unrealize(MMHandleType player) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_mused_gst_pause(player); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -static MMHandleType _mmplayer_mused_construct_attribute(mm_player_t *player) -{ - int idx = 0; - MMHandleType attrs = 0; - int num_of_attrs = 0; - mmf_attrs_construct_info_t *base = NULL; - - MMPlayerAttrsSpec player_attrs[] = - { - { - "display_surface_type", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) MM_DISPLAY_SURFACE_NULL, - MM_ATTRS_VALID_TYPE_INT_RANGE, - MM_DISPLAY_SURFACE_X, - MM_DISPLAY_SURFACE_X_EXT - }, - { - "display_overlay", - MM_ATTRS_TYPE_DATA, - MM_ATTRS_FLAG_RW, - (void *) NULL, - MM_ATTRS_VALID_TYPE_NONE, - 0, - 0 - }, -#ifdef HAVE_WAYLAND - { - "wl_display", - MM_ATTRS_TYPE_DATA, - MM_ATTRS_FLAG_RW, - (void *) NULL, - MM_ATTRS_VALID_TYPE_NONE, - 0, - 0 - }, - { - "wl_window_render_x", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) 0, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - MMPLAYER_MAX_INT - }, - { - "wl_window_render_y", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) 0, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - MMPLAYER_MAX_INT - }, - { - "wl_window_render_width", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) 0, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - MMPLAYER_MAX_INT - }, - { - "wl_window_render_height", - MM_ATTRS_TYPE_INT, - MM_ATTRS_FLAG_RW, - (void *) 0, - MM_ATTRS_VALID_TYPE_INT_RANGE, - 0, - MMPLAYER_MAX_INT - }, -#endif - { - "shm_stream_path", - MM_ATTRS_TYPE_STRING, - MM_ATTRS_FLAG_RW, - (void *) NULL, - MM_ATTRS_VALID_TYPE_NONE, - 0, - 0 - } - }; - num_of_attrs = ARRAY_SIZE(player_attrs); - base = (mmf_attrs_construct_info_t* )malloc(num_of_attrs * sizeof(mmf_attrs_construct_info_t)); - if ( !base ) - { - debug_error("failed to alloc attrs constructor"); - return 0; - } - - /* initialize values of attributes */ - for ( idx = 0; idx < num_of_attrs; idx++ ) - { - base[idx].name = player_attrs[idx].name; - base[idx].value_type = player_attrs[idx].value_type; - base[idx].flags = player_attrs[idx].flags; - base[idx].default_value = player_attrs[idx].default_value; - } - - attrs = mmf_attrs_new_from_data( - "mmplayer_attrs", - base, - num_of_attrs, - NULL, - NULL); - - /* clean */ - MMPLAYER_FREEIF(base); - - if ( !attrs ) - { - debug_error("failed to create player attrs"); - return 0; - } - - /* set validity type and range */ - for ( idx = 0; idx < num_of_attrs; idx++ ) - { - switch ( player_attrs[idx].valid_type) - { - case MM_ATTRS_VALID_TYPE_INT_RANGE: - { - mmf_attrs_set_valid_type (attrs, idx, MM_ATTRS_VALID_TYPE_INT_RANGE); - mmf_attrs_set_valid_range (attrs, idx, - player_attrs[idx].value_min, - player_attrs[idx].value_max, - (int)(intptr_t)(player_attrs[idx].default_value)); - } - break; - - case MM_ATTRS_VALID_TYPE_INT_ARRAY: - case MM_ATTRS_VALID_TYPE_DOUBLE_ARRAY: - case MM_ATTRS_VALID_TYPE_DOUBLE_RANGE: - default: - break; - } - } - - /* commit */ - mmf_attrs_commit(attrs); - - return attrs; -} - -/* - * Server uses functions - */ -int mm_player_get_raw_video_caps(MMHandleType player, char **caps) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(caps, MM_ERROR_PLAYER_NOT_INITIALIZED); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_get_raw_video_caps(player, caps); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; -} - -static int _mmplayer_get_raw_video_caps(mm_player_t *player, char **caps) -{ - GstCaps *v_caps = NULL; - GstPad *pad = NULL; - GstElement *gst; - gint stype = 0; - - if(!player->videosink_linked) { - debug_log("No video sink"); - return MM_ERROR_NONE; - } - mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype); - - if (stype == MM_DISPLAY_SURFACE_NULL) { - debug_log("Display type is NULL"); - if(!player->video_fakesink) { - debug_error("No fakesink"); - return MM_ERROR_PLAYER_INVALID_STATE; - } - gst = player->video_fakesink; - } - else { - if ( !player->pipeline || !player->pipeline->videobin || - !player->pipeline->videobin[MMPLAYER_V_SINK].gst ) { - debug_error("No video pipeline"); - return MM_ERROR_PLAYER_INVALID_STATE; - } - gst = player->pipeline->videobin[MMPLAYER_V_SINK].gst; - } - pad = gst_element_get_static_pad(gst, "sink"); - if(!pad) { - debug_error("static pad is NULL"); - return MM_ERROR_PLAYER_INVALID_STATE; - } - v_caps = gst_pad_get_current_caps(pad); - gst_object_unref( pad ); - - if(!v_caps) { - debug_error("fail to get caps"); - return MM_ERROR_PLAYER_INVALID_STATE; - } - - *caps = gst_caps_to_string(v_caps); - - gst_caps_unref(v_caps); - - return MM_ERROR_NONE; -} - -/* - * Server and client both use functions - */ -int mm_player_set_shm_stream_path(MMHandleType player, const char *path) -{ - int result = MM_ERROR_NONE; - - return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - return_val_if_fail(path, MM_ERROR_INVALID_ARGUMENT); - - MMPLAYER_CMD_LOCK( player ); - - result = _mmplayer_set_shm_stream_path(player, path); - - MMPLAYER_CMD_UNLOCK( player ); - - return result; - -} - -static int _mmplayer_set_shm_stream_path(MMHandleType hplayer, const char *path) -{ - mm_player_t* player = (mm_player_t*) hplayer; - int result; - - MMPLAYER_FENTER(); - - return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - return_val_if_fail(path, MM_ERROR_INVALID_ARGUMENT); - - result = mm_attrs_set_string_by_name(player->attrs, "shm_stream_path", path) - - MMPLAYER_FLEAVE(); - return result; -} diff --git a/src/server/mm_player.c b/src/server/mm_player.c new file mode 100644 index 0000000..ac25a0d --- /dev/null +++ b/src/server/mm_player.c @@ -0,0 +1,1301 @@ +/* + * libmm-player + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , YeJin Cho , + * Seungbae Shin , YoungHwan An + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include + +#include +#include + +#include "mm_player.h" +#include "mm_player_priv.h" +#include "mm_player_attrs.h" +#include "mm_player_utils.h" +#include "mm_player_ini.h" +#include "mm_debug.h" +#include "mm_player_capture.h" +#include "mm_player_tracks.h" +#include "mm_player_es.h" + +int mm_player_create(MMHandleType *player) +{ + int result = MM_ERROR_NONE; + mm_player_t* new_player = NULL; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + + /* alloc player structure */ + new_player = g_malloc(sizeof(mm_player_t)); + if ( ! new_player ) + { + debug_error("Cannot allocate memory for player\n"); + goto ERROR; + } + memset(new_player, 0, sizeof(mm_player_t)); + + /* create player lock */ + g_mutex_init(&new_player->cmd_lock); + + /* create player lock */ + g_mutex_init(&new_player->playback_lock); + + + /* create msg callback lock */ + g_mutex_init(&new_player->msg_cb_lock); + + /* load ini files */ + result = mm_player_ini_load(&new_player->ini); + if(result != MM_ERROR_NONE) + { + debug_error("can't load ini"); + goto ERROR; + } + + result = mm_player_audio_effect_ini_load(&new_player->ini); + if(result != MM_ERROR_NONE) + { + debug_error("can't load audio ini"); + goto ERROR; + } + + + /* create player */ + result = _mmplayer_create_player((MMHandleType)new_player); + + if(result != MM_ERROR_NONE) + { + debug_error("failed to create player"); + goto ERROR; + } + + *player = (MMHandleType)new_player; + + return result; + +ERROR: + + if ( new_player ) + { + _mmplayer_destroy( (MMHandleType)new_player ); + g_mutex_clear(&new_player->cmd_lock); + g_mutex_clear(&new_player->playback_lock); + + MMPLAYER_FREEIF( new_player ); + } + + *player = (MMHandleType)0; + return MM_ERROR_PLAYER_NO_FREE_SPACE; // are you sure? +} + +int mm_player_destroy(MMHandleType player) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_destroy(player); + + MMPLAYER_CMD_UNLOCK( player ); + + g_mutex_clear(&((mm_player_t*)player)->cmd_lock); + g_mutex_clear(&((mm_player_t*)player)->playback_lock); + + memset( (mm_player_t*)player, 0x00, sizeof(mm_player_t) ); + + /* free player */ + g_free( (void*)player ); + + return result; +} + +int mm_player_realize(MMHandleType player) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_realize(player); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_unrealize(MMHandleType player) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_unrealize(player); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_message_callback(MMHandleType player, MMMessageCallback callback, void *user_param) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_message_callback(player, callback, user_param); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_pd_message_callback(MMHandleType player, MMMessageCallback callback, void *user_param) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + result = _mm_player_set_pd_downloader_message_cb(player, callback, user_param); + + return result; +} + +int mm_player_set_audio_stream_callback(MMHandleType player, mm_player_audio_stream_callback callback, void *user_param) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_audiostream_cb(player, callback, user_param); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_audio_stream_callback_ex(MMHandleType player, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_audiostream_cb_ex(player, sync, callback, user_param); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_video_stream_callback(MMHandleType player, mm_player_video_stream_callback callback, void *user_param) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_videostream_cb(player, callback, user_param); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_video_frame_render_error_callback(MMHandleType player, mm_player_video_frame_render_error_callback callback, void *user_param) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_videoframe_render_error_cb(player, callback, user_param); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_do_video_capture(MMHandleType player) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_do_video_capture(player); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_prepare_buffering_time(MMHandleType player, int second) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_prepare_buffering_time(player, second); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_runtime_buffering_mode(MMHandleType player, MMPlayerBufferingMode mode, int second) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_runtime_buffering_mode(player, mode, second); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_volume(MMHandleType player, MMPlayerVolumeType *volume) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(volume, MM_ERROR_INVALID_ARGUMENT); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_volume(player, *volume); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_get_volume(MMHandleType player, MMPlayerVolumeType *volume) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(volume, MM_ERROR_INVALID_ARGUMENT); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_get_volume(player, volume); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_mute(MMHandleType player, int mute) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_mute(player, mute); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_get_mute(MMHandleType player, int *mute) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(mute, MM_ERROR_INVALID_ARGUMENT); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_get_mute(player, mute); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_get_state(MMHandleType player, MMPlayerStateType *state) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(state, MM_ERROR_COMMON_INVALID_ARGUMENT); + + *state = MM_PLAYER_STATE_NULL; + + result = _mmplayer_get_state(player, (int*)state); + + return result; +} + +/* NOTE : It does not support some use cases, eg using colorspace converter */ +int mm_player_change_videosink(MMHandleType player, MMDisplaySurfaceType display_surface_type, void *display_overlay) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_change_videosink(player, display_surface_type, display_overlay); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_push_buffer(MMHandleType player, unsigned char *buf, int size) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + //MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_push_buffer(player, buf, size); + + //MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_start(MMHandleType player) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_start(player); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_stop(MMHandleType player) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_stop(player); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_pause(MMHandleType player) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_pause(player); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_resume(MMHandleType player) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_resume(player); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_activate_section_repeat(MMHandleType player, int start_pos, int end_pos) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_activate_section_repeat(player, start_pos, end_pos); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_deactivate_section_repeat(MMHandleType player) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_deactivate_section_repeat(player); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_gst_set_audio_channel(MMHandleType player, MMPlayerAudioChannel ch) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_gst_set_audio_channel(player, ch); + + MMPLAYER_CMD_UNLOCK( player ); + return result; +} + +int mm_player_set_play_speed(MMHandleType player, float rate) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_playspeed(player, rate); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_position(MMHandleType player, MMPlayerPosFormatType format, int pos) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + if (format >= MM_PLAYER_POS_FORMAT_NUM) + { + debug_error("wrong format\n"); + return MM_ERROR_COMMON_INVALID_ARGUMENT; + } + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_position(player, format, pos); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_get_position(MMHandleType player, MMPlayerPosFormatType format, int *pos) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(pos, MM_ERROR_COMMON_INVALID_ARGUMENT); + + if (format >= MM_PLAYER_POS_FORMAT_NUM) + { + debug_error("wrong format\n"); + return MM_ERROR_COMMON_INVALID_ARGUMENT; + } + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_get_position(player, (int)format, (unsigned long*)pos); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_get_buffer_position(MMHandleType player, MMPlayerPosFormatType format, int *start_pos, int *stop_pos) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(start_pos && stop_pos, MM_ERROR_COMMON_INVALID_ARGUMENT); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_get_buffer_position(player, (int)format, (unsigned long*)start_pos, (unsigned long*)stop_pos ); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_external_subtitle_path(MMHandleType player, const char* path) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_external_subtitle_path(player, path); + + MMPLAYER_CMD_UNLOCK( player ); + return result; +} + +int mm_player_adjust_subtitle_position(MMHandleType player, MMPlayerPosFormatType format, int pos) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + if (format >= MM_PLAYER_POS_FORMAT_NUM) + { + debug_error("wrong format(%d) \n", format); + return MM_ERROR_INVALID_ARGUMENT; + } + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_adjust_subtitle_postion(player, format, pos); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_adjust_video_position(MMHandleType player, int offset) +{ + int result = MM_ERROR_NONE; + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_adjust_video_postion(player, offset); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_subtitle_silent(MMHandleType player, int silent) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_subtitle_silent(player, silent); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_get_subtitle_silent(MMHandleType player, int* silent) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_get_subtitle_silent(player, silent); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_attribute(MMHandleType player, char **err_attr_name, const char *first_attribute_name, ...) +{ + int result = MM_ERROR_NONE; + va_list var_args; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(first_attribute_name, MM_ERROR_COMMON_INVALID_ARGUMENT); + + va_start (var_args, first_attribute_name); + result = _mmplayer_set_attribute(player, err_attr_name, first_attribute_name, var_args); + va_end (var_args); + + return result; +} + +int mm_player_get_attribute(MMHandleType player, char **err_attr_name, const char *first_attribute_name, ...) +{ + int result = MM_ERROR_NONE; + va_list var_args; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(first_attribute_name, MM_ERROR_COMMON_INVALID_ARGUMENT); + + va_start (var_args, first_attribute_name); + result = _mmplayer_get_attribute(player, err_attr_name, first_attribute_name, var_args); + va_end (var_args); + + return result; +} + +int mm_player_get_attribute_info(MMHandleType player, const char *attribute_name, MMPlayerAttrsInfo *info) +{ + int result = MM_ERROR_NONE; + + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(attribute_name, MM_ERROR_COMMON_INVALID_ARGUMENT); + return_val_if_fail(info, MM_ERROR_COMMON_INVALID_ARGUMENT); + + result = _mmplayer_get_attributes_info((MMHandleType)player, attribute_name, info); + + return result; +} + +int mm_player_get_pd_status(MMHandleType player, guint64 *current_pos, guint64 *total_size) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(current_pos, MM_ERROR_COMMON_INVALID_ARGUMENT); + return_val_if_fail(total_size, MM_ERROR_COMMON_INVALID_ARGUMENT); + + result = _mmplayer_get_pd_downloader_status(player, current_pos, total_size); + + return result; +} + +int mm_player_get_track_count(MMHandleType player, MMPlayerTrackType type, int *count) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(count, MM_ERROR_COMMON_INVALID_ARGUMENT); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_get_track_count(player, type, count); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_select_track(MMHandleType player, MMPlayerTrackType type, int index) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_select_track(player, type, index); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} +#ifdef _MULTI_TRACK +int mm_player_track_add_subtitle_language(MMHandleType player, int index) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_track_add_subtitle_language(player, index); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_track_remove_subtitle_language(MMHandleType player, int index) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_track_remove_subtitle_language(player, index); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; + +} +#endif +int mm_player_get_current_track(MMHandleType player, MMPlayerTrackType type, int *index) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(index, MM_ERROR_COMMON_INVALID_ARGUMENT); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_get_current_track(player, type, index); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_get_track_language_code(MMHandleType player, MMPlayerTrackType type, int index, char **code) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_get_track_language_code(player, type, index, code); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_display_zoom(MMHandleType player, float level, int x, int y) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_display_zoom(player, level, x, y); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_get_display_zoom(MMHandleType player, float *level, int *x, int *y) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(level, MM_ERROR_COMMON_INVALID_ARGUMENT); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_get_display_zoom(player, level, x, y); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + + +int mm_player_use_system_clock(MMHandleType player) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_use_system_clock(player); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_video_share_master_clock(MMHandleType player, + long long clock, + long long clock_delta, + long long video_time, + long long media_clock, + long long audio_time) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_video_share_master_clock(player, clock, clock_delta, video_time, media_clock, audio_time); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_get_video_share_master_clock(MMHandleType player, + long long *video_time, + long long *media_clock, + long long *audio_time) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT); + return_val_if_fail(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT); + return_val_if_fail(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_get_video_share_master_clock(player, video_time, media_clock, audio_time); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_get_video_rotate_angle(MMHandleType player, int *angle) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(angle, MM_ERROR_COMMON_INVALID_ARGUMENT); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_get_video_rotate_angle(player, angle); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_video_hub_download_mode(MMHandleType player, bool mode) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_video_hub_download_mode(player, mode); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_enable_sync_handler(MMHandleType player, bool enable) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_enable_sync_handler(player, enable); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_uri(MMHandleType player, const char *uri) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_uri(player, uri); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; + +} + +int mm_player_set_next_uri(MMHandleType player, const char *uri) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_next_uri(player, uri, FALSE); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; + +} + +int mm_player_get_next_uri(MMHandleType player, char **uri) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_get_next_uri(player, uri); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; + +} +#ifdef _MULTI_TRACK +int mm_player_track_foreach_selected_subtitle_language(MMHandleType player, mm_player_track_selected_subtitle_language_callback callback, void *user_param) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_track_foreach_selected_subtitle_language(player, callback, user_param); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} +#endif + +int mm_player_has_closed_caption(MMHandleType player, bool *exist) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(exist, MM_ERROR_INVALID_ARGUMENT); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_has_closed_caption(player, exist); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_enable_media_packet_video_stream(MMHandleType player, bool enable) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(enable, MM_ERROR_INVALID_ARGUMENT); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_enable_media_packet_video_stream(player, enable); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +void * mm_player_media_packet_video_stream_internal_buffer_ref(void *buffer) +{ + void * result; + result = _mm_player_media_packet_video_stream_internal_buffer_ref(buffer); + + return result; +} + +void mm_player_media_packet_video_stream_internal_buffer_unref(void *buffer) +{ + _mm_player_media_packet_video_stream_internal_buffer_unref(buffer); +} + +int mm_player_submit_packet(MMHandleType player, media_packet_h packet) +{ + + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + /* no lock here, otherwise callback for the "need-data" signal of appsrc will be blocking */ + //MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_submit_packet(player, packet); + + //MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_video_info (MMHandleType player, media_format_h format) +{ + int result = MM_ERROR_NONE; + + debug_log("\n"); + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_video_info(player, format); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; + +} + +int mm_player_set_audio_info (MMHandleType player, media_format_h format) +{ + int result = MM_ERROR_NONE; + + debug_log("\n"); + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_audio_info(player, format); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_subtitle_info (MMHandleType player, MMPlayerSubtitleStreamInfo *subtitle_stream_info) +{ + int result = MM_ERROR_NONE; + + debug_log("\n"); + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_subtitle_info(player, subtitle_stream_info); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_media_stream_buffer_max_size(MMHandleType player, MMPlayerStreamType type, unsigned long long max_size) +{ + int result = MM_ERROR_NONE; + + debug_log("\n"); + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_media_stream_max_size(player, type, max_size); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_get_media_stream_buffer_max_size(MMHandleType player, MMPlayerStreamType type, unsigned long long *max_size) +{ + int result = MM_ERROR_NONE; + guint64 _max_size = 0; + + debug_log("\n"); + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(max_size, MM_ERROR_INVALID_ARGUMENT); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_get_media_stream_max_size(player, type, &_max_size); + *max_size = _max_size; + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_media_stream_buffer_min_percent(MMHandleType player, MMPlayerStreamType type, unsigned min_percent) +{ + int result = MM_ERROR_NONE; + + debug_log("\n"); + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_media_stream_min_percent(player, type, min_percent); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_get_media_stream_buffer_min_percent(MMHandleType player, MMPlayerStreamType type, unsigned int *min_percent) +{ + int result = MM_ERROR_NONE; + + debug_log("\n"); + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(min_percent, MM_ERROR_INVALID_ARGUMENT); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_get_media_stream_min_percent(player, type, min_percent); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_media_stream_buffer_status_callback(MMHandleType player, MMPlayerStreamType type, mm_player_media_stream_buffer_status_callback callback, void * user_param) +{ + int result = MM_ERROR_NONE; + + debug_log("\n"); + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_media_stream_buffer_status_cb(player, type, callback, user_param); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_media_stream_seek_data_callback(MMHandleType player, MMPlayerStreamType type, mm_player_media_stream_seek_data_callback callback, void * user_param) +{ + int result = MM_ERROR_NONE; + + debug_log("\n"); + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_media_stream_seek_data_cb(player, type, callback, user_param); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_audio_stream_changed_callback(MMHandleType player, mm_player_stream_changed_callback callback, void *user_param) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_audiostream_changed_cb(player, callback, user_param); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_video_stream_changed_callback(MMHandleType player, mm_player_stream_changed_callback callback, void *user_param) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_videostream_changed_cb(player, callback, user_param); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_pcm_spec(MMHandleType player, int samplerate, int channel) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_pcm_spec(player, samplerate, channel); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} + +int mm_player_set_shm_stream_path(MMHandleType player, const char *path) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(path, MM_ERROR_INVALID_ARGUMENT); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_set_shm_stream_path(player, path); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; + +} + +int mm_player_get_raw_video_caps(MMHandleType player, char **caps) +{ + int result = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(caps, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_LOCK( player ); + + result = _mmplayer_get_raw_video_caps(player, caps); + + MMPLAYER_CMD_UNLOCK( player ); + + return result; +} \ No newline at end of file diff --git a/src/server/mm_player_audioeffect.c b/src/server/mm_player_audioeffect.c new file mode 100644 index 0000000..ab90b2d --- /dev/null +++ b/src/server/mm_player_audioeffect.c @@ -0,0 +1,1087 @@ +/* + * libmm-player + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi ,YeJin Cho , YoungHwan An + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include + +#include "mm_player_utils.h" +#include "mm_player_audioeffect.h" +#include "mm_player_ini.h" +#include "mm_player_priv.h" +#include + + +int +mm_player_get_foreach_present_supported_effect_type(MMHandleType hplayer, MMAudioEffectType effect_type, mmplayer_supported_audio_effect_cb foreach_cb, void *user_data) +{ + mm_player_t *player = NULL; + int result = MM_ERROR_NONE; + mm_sound_device_flags_e flags = MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG | MM_SOUND_DEVICE_STATE_ACTIVATED_FLAG; + MMSoundDeviceList_t device_list; + MMSoundDevice_t device_h = NULL; + mm_sound_device_type_e device_type; + int i = 0; + + MMPLAYER_FENTER(); + + return_val_if_fail ( hplayer, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + player = MM_PLAYER_CAST(hplayer); + + /* get status if speaker is activated */ + /* (1) get current device list */ + result = mm_sound_get_current_device_list(flags, &device_list); + + if ( result ) { + debug_error("mm_sound_get_current_device_list() failed [%x]!!", result); + MMPLAYER_FLEAVE(); + return result; + } + + /* (2) get device handle of device list */ + result = mm_sound_get_next_device (device_list, &device_h); + + if ( result ) { + debug_error("mm_sound_get_next_device() failed [%x]!!", result); + MMPLAYER_FLEAVE(); + return result; + } + + /* (3) get device type */ + result = mm_sound_get_device_type(device_h, &device_type); + + if ( result ) { + debug_error("mm_sound_get_device_type() failed [%x]!!", result); + MMPLAYER_FLEAVE(); + return result; + } + + /* preset */ + if (effect_type == MM_AUDIO_EFFECT_TYPE_PRESET) + { + for ( i = 0; i < MM_AUDIO_EFFECT_PRESET_NUM; i++ ) + { + if (player->ini.audio_effect_preset_list[i] ) + { + if (device_type == MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER && + player->ini.audio_effect_preset_earphone_only_list[i]) + { + continue; + } + if (!foreach_cb(effect_type,i, user_data)) + { + goto CALLBACK_ERROR; + } + } + } + } + /* custom */ + else if (effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) + { + for ( i = 0; i < MM_AUDIO_EFFECT_CUSTOM_NUM; i++ ) + { + if (player->ini.audio_effect_custom_list[i] ) + { + if (device_type == MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER && + player->ini.audio_effect_custom_earphone_only_list[i]) + { + continue; + } + if (!foreach_cb(effect_type,i, user_data)) + { + goto CALLBACK_ERROR; + } + } + } + } + else + { + debug_error("invalid effect type(%d)", effect_type); + result = MM_ERROR_INVALID_ARGUMENT; + } + + MMPLAYER_FLEAVE(); + + return result; + +CALLBACK_ERROR: + debug_error("foreach callback returned error"); + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_INTERNAL; +} + + +int +__mmplayer_set_harmony_effect(mm_player_t *player, GstElement *audio_effect_element) +{ + gint *ext_effect_level_list = NULL; + int count = 1; /* start from 1, because of excepting eq index */ + int ext_level_index = 0; + int result = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + return_val_if_fail ( audio_effect_element, MM_ERROR_INVALID_ARGUMENT ); + + /* Custom EQ */ + if( player->ini.audio_effect_custom_eq_band_num ) + { + debug_log("pass custom EQ level list to audio effect plugin"); + /* set custom-equalizer level list */ + g_object_set(audio_effect_element, "custom-eq", player->audio_effect_info.custom_eq_level, NULL); + } + else + { + debug_warning("no custom EQ"); + } + + /* Custom Extension effects */ + if( player->ini.audio_effect_custom_ext_num ) + { + debug_log("pass custom extension level list to audio effect plugin"); + ext_effect_level_list = player->audio_effect_info.custom_ext_level_for_plugin; + if (!ext_effect_level_list) { + ext_effect_level_list = (gint*) malloc (sizeof(gint)*player->ini.audio_effect_custom_ext_num); + if (!ext_effect_level_list) + { + debug_error("memory allocation for extension effect list failed"); + return MM_ERROR_OUT_OF_MEMORY; + } + else + { + memset (ext_effect_level_list, 0, player->ini.audio_effect_custom_ext_num); + + /* associate it to player handle */ + player->audio_effect_info.custom_ext_level_for_plugin = ext_effect_level_list; + } + } + + while ( count < MM_AUDIO_EFFECT_CUSTOM_NUM ) + { + if ( player->ini.audio_effect_custom_list[count] ) + { + ext_effect_level_list[ext_level_index] = player->audio_effect_info.custom_ext_level[count-1]; + ext_level_index++; + if (ext_level_index == player->ini.audio_effect_custom_ext_num) + { + break; + } + } + count++; + } + + /* set custom-extension effects level list */ + g_object_set(audio_effect_element, "custom-ext", ext_effect_level_list, NULL); + } + else + { + debug_warning("no custom extension effect"); + } + + /* order action to audio effect plugin */ + g_object_set(audio_effect_element, "filter-action", MM_AUDIO_EFFECT_TYPE_CUSTOM, NULL); + debug_log("filter-action = %d", MM_AUDIO_EFFECT_TYPE_CUSTOM); + + MMPLAYER_FLEAVE(); + + return result; +} + + +gboolean +__mmplayer_is_earphone_only_effect_type(mm_player_t *player, MMAudioEffectType effect_type, int effect) +{ + gboolean result = FALSE; + int i = 0; + + MMPLAYER_FENTER(); + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + /* preset */ + if (effect_type == MM_AUDIO_EFFECT_TYPE_PRESET) + { + if (player->ini.audio_effect_preset_earphone_only_list[effect]) + { + debug_msg("this preset effect(%d) is only available with earphone", effect); + result = TRUE; + } + } + /* custom */ + else if (effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) + { + for (i = 1; i < MM_AUDIO_EFFECT_CUSTOM_NUM; i++) /* it starts from 1(except testing for EQ) */ + { + if (player->ini.audio_effect_custom_earphone_only_list[i]) + { + /* check if the earphone only custom effect was set */ + if (player->audio_effect_info.custom_ext_level[i-1]) + { + debug_msg("this custom effect(%d) is only available with earphone", i); + result = TRUE; + } + } + } + } + else + { + debug_error("invalid effect type(%d)", effect_type); + } + + MMPLAYER_FLEAVE(); + + return result; +} + +int +__mmplayer_audio_set_output_type (mm_player_t *player, MMAudioEffectType effect_type, int effect) +{ + GstElement *audio_effect_element = NULL; + mm_sound_device_flags_e flags = MM_SOUND_DEVICE_ALL_FLAG; + MMSoundDeviceList_t device_list; + MMSoundDevice_t device_h = NULL; + mm_sound_device_type_e device_type; + int output_type = 0; + int result = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + audio_effect_element = player->pipeline->audiobin[MMPLAYER_A_FILTER].gst; + + /* (1) get current device list */ + result = mm_sound_get_current_device_list(flags, &device_list); + + if ( result ) { + debug_error("mm_sound_get_current_device_list() failed [%x]!!", result); + MMPLAYER_FLEAVE(); + return result; + } + + /* (2) get device handle of device list */ + result = mm_sound_get_next_device (device_list, &device_h); + + if ( result ) { + debug_error("mm_sound_get_next_device() failed [%x]!!", result); + MMPLAYER_FLEAVE(); + return result; + } + + /* (3) get device type */ + result = mm_sound_get_device_type(device_h, &device_type); + + if ( result ) { + debug_error("mm_sound_get_device_type() failed [%x]!!", result); + MMPLAYER_FLEAVE(); + return result; + } + + /* SPEAKER case */ + if (device_type == MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER) + { + if ( MM_AUDIO_EFFECT_TYPE_SQUARE != effect_type ) { + if (__mmplayer_is_earphone_only_effect_type(player, effect_type, effect)) + { + debug_error("earphone is not equipped, this filter will not be applied"); + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_SOUND_EFFECT_INVALID_STATUS; + } + } + + output_type = MM_AUDIO_EFFECT_OUTPUT_SPK; + } + else if (device_type == MM_SOUND_DEVICE_TYPE_MIRRORING) + { + output_type = MM_AUDIO_EFFECT_OUTPUT_OTHERS; + } + else if (device_type == MM_SOUND_DEVICE_TYPE_HDMI) + { + output_type = MM_AUDIO_EFFECT_OUTPUT_HDMI; + } + else if (device_type == MM_SOUND_DEVICE_TYPE_BLUETOOTH) + { + output_type = MM_AUDIO_EFFECT_OUTPUT_BT; + } + else if (device_type == MM_SOUND_DEVICE_TYPE_USB_AUDIO) + { + output_type = MM_AUDIO_EFFECT_OUTPUT_USB_AUDIO; + } + /* Other case, include WIRED_ACCESSORY */ + else + { + output_type = MM_AUDIO_EFFECT_OUTPUT_EAR; + } + debug_warning("output_type = %d (0:spk,1:ear,2:others)", output_type); + + /* set filter output mode */ + g_object_set(audio_effect_element, "filter-output-mode", output_type, NULL); + + return result; +} + +gboolean +_mmplayer_is_supported_effect_type(mm_player_t* player, MMAudioEffectType effect_type, int effect) +{ + gboolean result = TRUE; + mm_sound_device_flags_e flags = MM_SOUND_DEVICE_ALL_FLAG; + MMSoundDeviceList_t device_list; + MMSoundDevice_t device_h = NULL; + mm_sound_device_type_e device_type; + int ret = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + /* get status if speaker is activated */ + /* (1) get current device list */ + ret = mm_sound_get_current_device_list(flags, &device_list); + if (ret) { + MMPLAYER_FLEAVE(); + debug_error("mm_sound_get_current_device_list() failed [%x]!!", ret); + return FALSE; + } + + /* (2) get device handle of device list */ + ret = mm_sound_get_next_device (device_list, &device_h); + + if (ret) { + debug_error("mm_sound_get_next_device() failed [%x]!!", ret); + MMPLAYER_FLEAVE(); + return FALSE; + } + + /* (3) get device type */ + ret = mm_sound_get_device_type(device_h, &device_type); + + if (ret) { + debug_error("mm_sound_get_device_type() failed [%x]!!", ret); + MMPLAYER_FLEAVE(); + return FALSE; + } + + /* preset */ + if (effect_type == MM_AUDIO_EFFECT_TYPE_PRESET) + { + if ( effect < MM_AUDIO_EFFECT_PRESET_AUTO || effect >= MM_AUDIO_EFFECT_PRESET_NUM ) + { + debug_error("out of range, preset effect(%d)", effect); + result = FALSE; + } + else + { + if (!player->ini.audio_effect_preset_list[effect]) + { + debug_error("this effect(%d) is not supported", effect); + result = FALSE; + } + else + { + if (device_type == MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER && + player->ini.audio_effect_preset_earphone_only_list[effect]) + { + result = FALSE; + } + } + } + } + /* custom */ + else if (effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) + { + if ( effect < MM_AUDIO_EFFECT_CUSTOM_EQ || effect >= MM_AUDIO_EFFECT_CUSTOM_NUM ) + { + debug_error("out of range, custom effect(%d)", effect); + result = FALSE; + } + else + { + if (!player->ini.audio_effect_custom_list[effect]) + { + debug_error("this custom effect(%d) is not supported", effect); + result = FALSE; + } + else + { + if (device_type == MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER && + player->ini.audio_effect_custom_earphone_only_list[effect]) + { + result = FALSE; + } + } + } + } + else if (effect_type == MM_AUDIO_EFFECT_TYPE_SQUARE) + { + if (!player->ini.use_audio_effect_custom) + { + debug_error("Square effect is not supported"); + result = FALSE; + } + } + else + { + debug_error("invalid effect type(%d)", effect_type); + result = FALSE; + } + + + MMPLAYER_FLEAVE(); + + return result; +} + +int +_mmplayer_audio_effect_custom_apply(mm_player_t *player) +{ + GstElement *audio_effect_element = NULL; + int result = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + /* Music Player can set audio effect value before Audiobin is created. */ + if ( !player->pipeline || !player->pipeline->audiobin || !player->pipeline->audiobin[MMPLAYER_A_FILTER].gst ) + { + debug_warning("effect element is not created yet."); + + player->bypass_audio_effect = FALSE; + + /* store audio effect setting in order to apply it when audio effect plugin is created */ + player->audio_effect_info.effect_type = MM_AUDIO_EFFECT_TYPE_CUSTOM; + } + else + { + audio_effect_element = player->pipeline->audiobin[MMPLAYER_A_FILTER].gst; + + /* get status if speaker is activated */ + result = __mmplayer_audio_set_output_type(player, MM_AUDIO_EFFECT_TYPE_CUSTOM, 0); + + if ( result != MM_ERROR_NONE) { + debug_error("failed to set output mode"); + MMPLAYER_FLEAVE(); + return result; + } + + result = __mmplayer_set_harmony_effect(player, audio_effect_element); + if ( result ) + { + debug_error("_set_harmony_effect() failed(%x)", result); + MMPLAYER_FLEAVE(); + return result; + } + } + player->set_mode.rich_audio = TRUE; + + MMPLAYER_FLEAVE(); + + return result; +} + +int +_mmplayer_audio_effect_custom_update_level(mm_player_t *player) +{ + GstElement *audio_effect_element = NULL; + int result = MM_ERROR_NONE; + int ext_level_index = 0; + int count = 1; + int i = 0; + gint *custom_eq = NULL; + gint *custom_ext_effect_level_list = NULL; + + MMPLAYER_FENTER(); + + return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + audio_effect_element = player->pipeline->audiobin[MMPLAYER_A_FILTER].gst; + + /* get custom eq effect */ + g_object_get(audio_effect_element, "custom-eq", &custom_eq, NULL); + + memcpy(player->audio_effect_info.custom_eq_level, custom_eq, sizeof(gint) * player->ini.audio_effect_custom_eq_band_num); + + for (i=0; iini.audio_effect_custom_eq_band_num;i++) + { + debug_log("updated custom-eq [%d] = %d", i, player->audio_effect_info.custom_eq_level[i]); + } + + /* get custom ext effect */ + + g_object_get(audio_effect_element, "custom-ext", &custom_ext_effect_level_list, NULL); + + while ( count < MM_AUDIO_EFFECT_CUSTOM_NUM ) + { + if ( player->ini.audio_effect_custom_list[count] ) + { + player->audio_effect_info.custom_ext_level[count-1] + = custom_ext_effect_level_list[ext_level_index]; + debug_log("updated custom-ext [%d] = %d", count, player->audio_effect_info.custom_ext_level[count-1]); + ext_level_index++; + } + count++; + } + + + MMPLAYER_FLEAVE(); + return result; +} + + +int +mm_player_audio_effect_custom_clear_eq_all(MMHandleType hplayer) +{ + int result = MM_ERROR_NONE; + mm_player_t* player = (mm_player_t*)hplayer; + + MMPLAYER_FENTER(); + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + /* clear EQ custom effect */ + memset(player->audio_effect_info.custom_eq_level, MM_AUDIO_EFFECT_CUSTOM_LEVEL_INIT, sizeof(int)*MM_AUDIO_EFFECT_EQ_BAND_NUM_MAX); + + debug_msg("All the EQ bands clearing success"); + + MMPLAYER_FLEAVE(); + + return result; +} + + +int +mm_player_audio_effect_custom_clear_ext_all(MMHandleType hplayer) +{ + int i; + int result = MM_ERROR_NONE; + mm_player_t* player = (mm_player_t*)hplayer; + + MMPLAYER_FENTER(); + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + /* clear ALL custom effects, except EQ */ + for ( i = 0 ; i < MM_AUDIO_EFFECT_CUSTOM_NUM - 1 ; i++ ) + { + player->audio_effect_info.custom_ext_level[i] = MM_AUDIO_EFFECT_CUSTOM_LEVEL_INIT; + } + + debug_msg("All the extension effects clearing success"); + + MMPLAYER_FLEAVE(); + + return result; +} + + +int +mm_player_is_supported_preset_effect_type(MMHandleType hplayer, MMAudioEffectPresetType effect) +{ + mm_player_t* player = (mm_player_t*)hplayer; + int result = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_PRESET, effect ) ) + { + result = MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; + } + + MMPLAYER_FLEAVE(); + + return result; +} + + +int +mm_player_is_supported_custom_effect_type(MMHandleType hplayer, MMAudioEffectCustomType effect) +{ + mm_player_t* player = (mm_player_t*)hplayer; + int result = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_CUSTOM, effect ) ) + { + result = MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; + } + + MMPLAYER_FLEAVE(); + + return result; +} + +int +mm_player_audio_effect_custom_apply(MMHandleType hplayer) +{ + mm_player_t* player = (mm_player_t*)hplayer; + int result = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + if (!player->ini.use_audio_effect_custom) + { + debug_error("audio effect(custom) is not supported"); + MMPLAYER_FLEAVE(); + return MM_ERROR_NOT_SUPPORT_API; + } + + result = _mmplayer_audio_effect_custom_apply(player); + + MMPLAYER_FLEAVE(); + + return result; +} + + +int +mm_player_audio_effect_bypass (MMHandleType hplayer) +{ + mm_player_t* player = (mm_player_t*)hplayer; + int result = MM_ERROR_NONE; + GstElement *audio_effect_element = NULL; + + MMPLAYER_FENTER(); + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + if ( !player->ini.use_audio_effect_preset && !player->ini.use_audio_effect_custom ) + { + debug_error("audio effect(preset/custom) is not supported"); + MMPLAYER_FLEAVE(); + return MM_ERROR_NOT_SUPPORT_API; + } + if ( !player->pipeline || !player->pipeline->audiobin || !player->pipeline->audiobin[MMPLAYER_A_FILTER].gst ) + { + debug_warning("effect element is not created yet."); + } + else + { + audio_effect_element = player->pipeline->audiobin[MMPLAYER_A_FILTER].gst; + + /* order action to audio effect plugin */ + g_object_set(audio_effect_element, "filter-action", MM_AUDIO_EFFECT_TYPE_NONE, NULL); + debug_log("filter-action = %d", MM_AUDIO_EFFECT_TYPE_NONE); + } + + MMPLAYER_FLEAVE(); + + return result; +} + + +int +_mmplayer_audio_effect_custom_set_level_ext(mm_player_t *player, MMAudioEffectCustomType custom_effect_type, int level) +{ + int effect_level_max = 0; + int effect_level_min = 0; + int count = 1; /* start from 1, because of excepting eq index */ + int ext_level_index = 1; /* start from 1, because of excepting eq index */ + int result = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + /* check if EQ is supported */ + if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_CUSTOM, custom_effect_type ) ) + { + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; + } + + while ( count < MM_AUDIO_EFFECT_CUSTOM_NUM ) + { + if ( player->ini.audio_effect_custom_list[count] ) + { + if ( count == custom_effect_type ) + { + effect_level_min = player->ini.audio_effect_custom_min_level_list[ext_level_index]; + effect_level_max = player->ini.audio_effect_custom_max_level_list[ext_level_index]; + debug_msg("level min value(%d), level max value(%d)", effect_level_min, effect_level_max); + break; + } + ext_level_index++; + if (ext_level_index == player->ini.audio_effect_custom_ext_num + 1) + { + debug_error("could not find min, max value. maybe effect information in ini file is not proper for audio effect plugin"); + break; + } + } + count++; + } + + if ( level < effect_level_min || level > effect_level_max ) + { + debug_error("out of range, level(%d)", level); + result = MM_ERROR_INVALID_ARGUMENT; + } + else + { + player->audio_effect_info.custom_ext_level[custom_effect_type-1] = level; + debug_msg("set ext[%d] = %d", custom_effect_type-1, level); + } + + MMPLAYER_FLEAVE(); + + return result; +} + + +int +_mmplayer_audio_effect_custom_set_level_eq(mm_player_t *player, int index, int level) +{ + gint eq_level_max = 0; + gint eq_level_min = 0; + int result = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + /* check if EQ is supported */ + if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_CUSTOM, MM_AUDIO_EFFECT_CUSTOM_EQ ) ) + { + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; + } + + if ( index < 0 || index > player->ini.audio_effect_custom_eq_band_num - 1 ) + { + debug_error("out of range, index(%d)", index); + result = MM_ERROR_INVALID_ARGUMENT; + } + else + { + eq_level_min = player->ini.audio_effect_custom_min_level_list[MM_AUDIO_EFFECT_CUSTOM_EQ]; + eq_level_max = player->ini.audio_effect_custom_max_level_list[MM_AUDIO_EFFECT_CUSTOM_EQ]; + debug_msg("EQ level min value(%d), EQ level max value(%d)", eq_level_min, eq_level_max); + + if ( level < eq_level_min || level > eq_level_max ) + { + debug_error("out of range, EQ level(%d)", level); + result = MM_ERROR_INVALID_ARGUMENT; + } + else + { + player->audio_effect_info.custom_eq_level[index] = level; + debug_msg("set EQ[%d] = %d", index, level); + } + } + + MMPLAYER_FLEAVE(); + + return result; +} + + +/* NOTE : parameter eq_index is only used for _set_eq_level() */ +int +mm_player_audio_effect_custom_set_level(MMHandleType hplayer, MMAudioEffectCustomType effect_custom_type, int eq_index, int level) +{ + mm_player_t* player = (mm_player_t*)hplayer; + int result = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + /* check if this effect type is supported */ + if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_CUSTOM, effect_custom_type ) ) + { + result = MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; + } + else + { + if (effect_custom_type == MM_AUDIO_EFFECT_CUSTOM_EQ) + { + result = _mmplayer_audio_effect_custom_set_level_eq(player, eq_index, level); + } + else if (effect_custom_type > MM_AUDIO_EFFECT_CUSTOM_EQ && effect_custom_type < MM_AUDIO_EFFECT_CUSTOM_NUM) + { + result = _mmplayer_audio_effect_custom_set_level_ext(player, effect_custom_type, level); + } + else + { + debug_error("out of range, effect type(%d)", effect_custom_type); + result = MM_ERROR_INVALID_ARGUMENT; + } + } + + MMPLAYER_FLEAVE(); + + return result; +} + + +int +mm_player_audio_effect_custom_get_eq_bands_number(MMHandleType hplayer, int *bands) +{ + mm_player_t* player = (mm_player_t*)hplayer; + int result = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + /* check if EQ is supported */ + if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_CUSTOM, MM_AUDIO_EFFECT_CUSTOM_EQ ) ) + { + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; + } + + *bands = player->ini.audio_effect_custom_eq_band_num; + debug_log("number of custom EQ band = %d", *bands); + + MMPLAYER_FLEAVE(); + + return result; +} + + +int +mm_player_audio_effect_custom_get_eq_bands_width(MMHandleType hplayer, int band_idx, int *width) +{ + mm_player_t* player = (mm_player_t*)hplayer; + int result = MM_ERROR_NONE; + unsigned int eq_num = 0; + + MMPLAYER_FENTER(); + + return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + /* check if EQ is supported */ + if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_CUSTOM, MM_AUDIO_EFFECT_CUSTOM_EQ ) ) + { + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; + } + + eq_num = player->ini.audio_effect_custom_eq_band_num; + if (band_idx < 0 || band_idx > eq_num-1) + { + debug_error("out of range, invalid band_idx(%d)", band_idx); + result = MM_ERROR_INVALID_ARGUMENT; + } + else + { + /* set the width of EQ band */ + *width = player->ini.audio_effect_custom_eq_band_width[band_idx]; + debug_log("width of band_idx(%d) = %dHz", band_idx, *width); + } + + MMPLAYER_FLEAVE(); + + return result; +} + + +int +mm_player_audio_effect_custom_get_eq_bands_freq(MMHandleType hplayer, int band_idx, int *freq) +{ + mm_player_t* player = (mm_player_t*)hplayer; + int result = MM_ERROR_NONE; + unsigned int eq_num = 0; + + MMPLAYER_FENTER(); + + return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + /* check if EQ is supported */ + if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_CUSTOM, MM_AUDIO_EFFECT_CUSTOM_EQ ) ) + { + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; + } + + eq_num = player->ini.audio_effect_custom_eq_band_num; + if (band_idx < 0 || band_idx > eq_num-1) + { + debug_error("out of range, invalid band_idx(%d)", band_idx); + result = MM_ERROR_INVALID_ARGUMENT; + } + else + { + /* set the frequency of EQ band */ + *freq = player->ini.audio_effect_custom_eq_band_freq[band_idx]; + debug_log("frequency of band_idx(%d) = %dHz", band_idx, *freq); + } + + MMPLAYER_FLEAVE(); + + return result; +} + + +int +mm_player_audio_effect_custom_get_level(MMHandleType hplayer, MMAudioEffectCustomType type, int eq_index, int *level) +{ + mm_player_t* player = (mm_player_t*)hplayer; + int result = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + return_val_if_fail( level, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + /* check if this effect type is supported */ + if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_CUSTOM, type ) ) + { + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; + } + + if (type == MM_AUDIO_EFFECT_CUSTOM_EQ) + { + if ( eq_index < 0 || eq_index > player->ini.audio_effect_custom_eq_band_num - 1 ) + { + debug_error("out of range, EQ index(%d)", eq_index); + result = MM_ERROR_INVALID_ARGUMENT; + } + else + { + *level = player->audio_effect_info.custom_eq_level[eq_index]; + debug_log("EQ index = %d, level = %d", eq_index, *level); + } + } + else if ( type > MM_AUDIO_EFFECT_CUSTOM_EQ && type < MM_AUDIO_EFFECT_CUSTOM_NUM ) + { + *level = player->audio_effect_info.custom_ext_level[type-1]; + debug_log("extension effect index = %d, level = %d", type, *level); + } + else + { + debug_error("out of range, type(%d)", type); + result = MM_ERROR_INVALID_ARGUMENT; + } + + MMPLAYER_FLEAVE(); + + return result; +} + + +int +mm_player_audio_effect_custom_get_level_range(MMHandleType hplayer, MMAudioEffectCustomType type, int *min, int *max) +{ + mm_player_t* player = (mm_player_t*)hplayer; + int result = MM_ERROR_NONE; + int count = 1; /* start from 1, because of excepting eq index */ + int ext_level_index = 1; /* start from 1, because of excepting eq index */ + + MMPLAYER_FENTER(); + + return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + return_val_if_fail( min, MM_ERROR_PLAYER_NOT_INITIALIZED ); + return_val_if_fail( max, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + /* check if this effect type is supported */ + if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_CUSTOM, type ) ) + { + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; + } + + if ( type == MM_AUDIO_EFFECT_CUSTOM_EQ ) + { + *min = player->ini.audio_effect_custom_min_level_list[MM_AUDIO_EFFECT_CUSTOM_EQ]; + *max = player->ini.audio_effect_custom_max_level_list[MM_AUDIO_EFFECT_CUSTOM_EQ]; + debug_log("EQ min level = %d, max level = %d", *min, *max); + } + else + { + while ( count < MM_AUDIO_EFFECT_CUSTOM_NUM ) + { + if ( player->ini.audio_effect_custom_list[count] ) + { + if ( count == type ) + { + *min = player->ini.audio_effect_custom_min_level_list[ext_level_index]; + *max = player->ini.audio_effect_custom_max_level_list[ext_level_index]; + debug_msg("Extension effect(%d) min level = %d, max level = %d", count, *min, *max); + break; + } + ext_level_index++; + if ( ext_level_index == player->ini.audio_effect_custom_ext_num + 1 ) + { + debug_error("could not find min, max value. maybe effect information in ini file is not proper for audio effect plugin"); + break; + } + } + count++; + } + } + + MMPLAYER_FLEAVE(); + + return result; +} + + +int +mm_player_audio_effect_custom_set_level_eq_from_list(MMHandleType hplayer, int *level_list, int size) +{ + mm_player_t *player = (mm_player_t*)hplayer; + gint i = 0; + gint eq_level_min = 0; + gint eq_level_max = 0; + int result = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + /* check if EQ is supported */ + if ( !_mmplayer_is_supported_effect_type( player, MM_AUDIO_EFFECT_TYPE_CUSTOM, MM_AUDIO_EFFECT_CUSTOM_EQ ) ) + { + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_SOUND_EFFECT_NOT_SUPPORTED_FILTER; + } + + if ( size != player->ini.audio_effect_custom_eq_band_num ) + { + debug_error("input size variable(%d) does not match with number of eq band(%d)", size, player->ini.audio_effect_custom_eq_band_num); + result = MM_ERROR_INVALID_ARGUMENT; + } + else + { + eq_level_min = player->ini.audio_effect_custom_min_level_list[MM_AUDIO_EFFECT_CUSTOM_EQ]; + eq_level_max = player->ini.audio_effect_custom_max_level_list[MM_AUDIO_EFFECT_CUSTOM_EQ]; + + for ( i = 0 ; i < size ; i++ ) + { + if ( level_list[i] < eq_level_min || level_list[i] > eq_level_max) + { + debug_error("out of range, level[%d]=%d", i, level_list[i]); + result = MM_ERROR_INVALID_ARGUMENT; + break; + } + player->audio_effect_info.custom_eq_level[i] = level_list[i]; + } + } + MMPLAYER_FLEAVE(); + + return result; +} diff --git a/src/server/mm_player_capture.c b/src/server/mm_player_capture.c new file mode 100644 index 0000000..1526cff --- /dev/null +++ b/src/server/mm_player_capture.c @@ -0,0 +1,954 @@ +/* + * libmm-player + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , YeJin Cho , + * Seungbae Shin , YoungHwan An + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*=========================================================================================== +| | +| INCLUDE FILES | +| | +========================================================================================== */ +#include "mm_player_utils.h" +#include "mm_player_capture.h" +#include "mm_player_priv.h" +#include "mm_player_utils.h" + +#include +#include + +/*--------------------------------------------------------------------------- +| LOCAL VARIABLE DEFINITIONS for internal | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| LOCAL FUNCTION PROTOTYPES: | +---------------------------------------------------------------------------*/ +static GstPadProbeReturn __mmplayer_video_capture_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data); +static int __mmplayer_get_video_frame_from_buffer(mm_player_t* player, GstPad *pad, GstBuffer *buffer); +static gpointer __mmplayer_capture_thread(gpointer data); +static void __csc_tiled_to_linear_crop(unsigned char *yuv420_dest, unsigned char *nv12t_src, int yuv420_width, int yuv420_height, int left, int top, int right, int buttom); +static int __tile_4x2_read(int x_size, int y_size, int x_pos, int y_pos); +static int __mm_player_convert_colorspace(mm_player_t* player, unsigned char* src_data, mm_util_img_format src_fmt, unsigned int src_w, unsigned int src_h, mm_util_img_format dst_fmt); + +/*=========================================================================================== +| | +| FUNCTION DEFINITIONS | +| | +========================================================================================== */ +int +_mmplayer_initialize_video_capture(mm_player_t* player) +{ + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + /* create capture mutex */ + g_mutex_init(&player->capture_thread_mutex); + + /* create capture cond */ + g_cond_init(&player->capture_thread_cond); + + + player->capture_thread_exit = FALSE; + + /* create video capture thread */ + player->capture_thread = + g_thread_try_new ("capture_thread",__mmplayer_capture_thread, (gpointer)player, NULL); + + if ( ! player->capture_thread ) + { + goto ERROR; + } + + return MM_ERROR_NONE; + +ERROR: + /* capture thread */ + g_mutex_clear(&player->capture_thread_mutex ); + + g_cond_clear (&player->capture_thread_cond ); + + return MM_ERROR_PLAYER_INTERNAL; +} + +int +_mmplayer_release_video_capture(mm_player_t* player) +{ + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + /* release capture thread */ + g_mutex_lock(&player->capture_thread_mutex); + player->capture_thread_exit = TRUE; + g_cond_signal( &player->capture_thread_cond ); + g_mutex_unlock(&player->capture_thread_mutex); + + debug_log("waitting for capture thread exit"); + g_thread_join ( player->capture_thread ); + g_mutex_clear(&player->capture_thread_mutex ); + g_cond_clear(&player->capture_thread_cond ); + debug_log("capture thread released"); + + return MM_ERROR_NONE; +} + +int +_mmplayer_do_video_capture(MMHandleType hplayer) +{ + mm_player_t* player = (mm_player_t*) hplayer; + int ret = MM_ERROR_NONE; + GstPad *pad = NULL; + + MMPLAYER_FENTER(); + + return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); + + /* capturing or not */ + if (player->video_capture_cb_probe_id || player->capture.data + || player->captured.data[0] || player->captured.data[1] + ) + { + debug_warning("capturing... we can't do any more"); + return MM_ERROR_PLAYER_INVALID_STATE; + } + + /* check if video pipeline is linked or not */ + if (!player->pipeline->videobin) + { + debug_warning("not ready to capture"); + return MM_ERROR_PLAYER_INVALID_STATE; + } + + /* check if drm file */ + if (player->is_drm_file) + { + debug_warning("not supported in drm file"); + return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION; + } + + pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink" ); + + if (player->state != MM_PLAYER_STATE_PLAYING) + { + if (player->state == MM_PLAYER_STATE_PAUSED) // get last buffer from video sink + { + GstSample *sample = NULL; + + gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, 5 * GST_SECOND); //5 seconds + + g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "last-sample", &sample, NULL); + + if (sample) + { + GstBuffer *buf = NULL; + buf = gst_sample_get_buffer(sample); + + if (buf) + { + ret = __mmplayer_get_video_frame_from_buffer(player, pad, buf); + } + else + { + debug_warning("failed to get video frame"); + } + gst_sample_unref(sample); + } + return ret; + } + else + { + debug_warning("invalid state(%d) to capture", player->state); + return MM_ERROR_PLAYER_INVALID_STATE; + } + } + + /* register probe */ + player->video_capture_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER, + __mmplayer_video_capture_probe, player, NULL); + + gst_object_unref(GST_OBJECT(pad)); + pad = NULL; + + MMPLAYER_FLEAVE(); + + return ret; +} + +int +__mmplayer_handle_orientation (mm_player_t* player, int orientation, int format) +{ + unsigned char *src_buffer = NULL; + int ret = MM_ERROR_NONE; + unsigned char *dst_frame = NULL; + unsigned int dst_width = 0; + unsigned int dst_height = 0; + unsigned int dst_size = 0; + mm_util_img_rotate_type rot_enum = MM_UTIL_ROTATE_NUM; + + player->capture.orientation = orientation; + + if (orientation == 90 || orientation == 270) + { + dst_width = player->captured.height[0]; + dst_height = player->captured.width[0]; + debug_log ("interchange width & height"); + } + else if (orientation == 180) + { + dst_width = player->captured.width[0]; + dst_height = player->captured.height[0]; + } + else if (orientation == 0) + { + debug_error ("no need handle orientation : %d", orientation); + player->capture.width = player->captured.width[0]; + player->capture.height = player->captured.height[0]; + return MM_ERROR_NONE; + } + else + { + debug_error ("wrong orientation value..."); + } + + /* height & width will be interchanged for 90 and 270 orientation */ + ret = mm_util_get_image_size(format, dst_width, dst_height, &dst_size); + if (ret != MM_ERROR_NONE) + { + debug_error("failed to get destination frame size"); + return ret; + } + + debug_log ("before rotation : dst_width = %d and dst_height = %d", dst_width, dst_height); + + dst_frame = (unsigned char*) malloc (dst_size); + if (!dst_frame) + { + debug_error("failed to allocate memory"); + return MM_ERROR_PLAYER_NO_FREE_SPACE; + } + + src_buffer = (unsigned char*)player->capture.data; + + /* convert orientation degree into enum here */ + switch(orientation) + { + case 0: + rot_enum = MM_UTIL_ROTATE_0; + break; + case 90: + rot_enum = MM_UTIL_ROTATE_90; + break; + case 180: + rot_enum = MM_UTIL_ROTATE_180; + break; + case 270: + rot_enum = MM_UTIL_ROTATE_270; + break; + default: + debug_error("wrong rotate value"); + break; + } + + debug_log ("source buffer for rotation = %p and rotation = %d", src_buffer, rot_enum); + + ret = mm_util_rotate_image (src_buffer, + player->captured.width[0], player->captured.height[0], format, + dst_frame, &dst_width, &dst_height, rot_enum); + if (ret != MM_ERROR_NONE) + { + debug_error("failed to do rotate image"); + return ret; + } + + debug_log ("after rotation same stride: dst_width = %d and dst_height = %d", dst_width, dst_height); + + g_free (src_buffer); + + player->capture.data = dst_frame; + player->capture.size = dst_size; + player->capture.orientation = orientation; + player->capture.width = dst_width; + player->capture.height= dst_height; + + player->captured.width[0] = player->captured.stride_width[0] = dst_width; + player->captured.height[0] = player->captured.stride_height[0] = dst_height; + + return ret; +} + + +static gpointer +__mmplayer_capture_thread(gpointer data) +{ + mm_player_t* player = (mm_player_t*) data; + MMMessageParamType msg = {0, }; + unsigned char * linear_y_plane = NULL; + unsigned char * linear_uv_plane = NULL; + int orientation = 0; + int ret = 0; + + return_val_if_fail(player, NULL); + + while (!player->capture_thread_exit) + { + debug_log("capture thread started. waiting for signal"); + + g_mutex_lock(&player->capture_thread_mutex); + g_cond_wait(&player->capture_thread_cond, &player->capture_thread_mutex ); + + if ( player->capture_thread_exit ) + { + debug_log("exiting capture thread"); + goto EXIT; + } + debug_log("capture thread is recieved signal"); + + /* NOTE: Don't use MMPLAYER_CMD_LOCK() here. + * Because deadlock can be happened if other player api is used in message callback. + */ + if (player->video_cs == MM_PLAYER_COLORSPACE_NV12_TILED) + { + /* Colorspace conversion : NV12T-> NV12-> RGB888 */ + int ret = 0; + int linear_y_plane_size; + int linear_uv_plane_size; + int width = player->captured.width[0]; + int height = player->captured.height[0]; + unsigned char * src_buffer = NULL; + + linear_y_plane_size = (width * height); + linear_uv_plane_size = (width * height / 2); + + linear_y_plane = (unsigned char*) g_try_malloc(linear_y_plane_size); + if (linear_y_plane == NULL) + { + msg.code = MM_ERROR_PLAYER_NO_FREE_SPACE; + goto ERROR; + } + + linear_uv_plane = (unsigned char*) g_try_malloc(linear_uv_plane_size); + if (linear_uv_plane == NULL) + { + msg.code = MM_ERROR_PLAYER_NO_FREE_SPACE; + goto ERROR; + } + /* NV12 tiled to linear */ + __csc_tiled_to_linear_crop(linear_y_plane, + player->captured.data[0], width, height, 0,0,0,0); + __csc_tiled_to_linear_crop(linear_uv_plane, + player->captured.data[1], width, height / 2, 0,0,0,0); + + MMPLAYER_FREEIF(player->captured.data[0]); + MMPLAYER_FREEIF(player->captured.data[1]); + + src_buffer = (unsigned char*) g_try_malloc(linear_y_plane_size+linear_uv_plane_size); + + if (src_buffer == NULL) + { + msg.code = MM_ERROR_PLAYER_NO_FREE_SPACE; + goto ERROR; + } + memset(src_buffer, 0x00, linear_y_plane_size+linear_uv_plane_size); + memcpy(src_buffer, linear_y_plane, linear_y_plane_size); + memcpy(src_buffer+linear_y_plane_size, linear_uv_plane, linear_uv_plane_size); + + /* NV12 linear to RGB888 */ + ret = __mm_player_convert_colorspace(player, src_buffer, MM_UTIL_IMG_FMT_NV12, + width, height, MM_UTIL_IMG_FMT_RGB888); + + if (ret != MM_ERROR_NONE) + { + debug_error("failed to convert nv12 linear"); + goto ERROR; + } + /* clean */ + MMPLAYER_FREEIF(src_buffer); + MMPLAYER_FREEIF(linear_y_plane); + MMPLAYER_FREEIF(linear_uv_plane); + } else if (MM_PLAYER_COLORSPACE_NV12 == player->video_cs) { + #define MM_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) + int ret = 0; + char *src_buffer = NULL; + /* using original width otherwises, app can't know aligned to resize */ + int width_align = player->captured.width[0]; + int src_buffer_size = width_align * player->captured.height[0] * 3/2; + int i, j; + char*temp = NULL; + char*dst_buf = NULL; + + if (!src_buffer_size) { + debug_error("invalid data size"); + goto ERROR; + } + + src_buffer = (char*) g_try_malloc(src_buffer_size); + + if (!src_buffer) { + msg.code = MM_ERROR_PLAYER_NO_FREE_SPACE; + goto ERROR; + } + + memset(src_buffer, 0x00, src_buffer_size); + + temp = player->captured.data[0]; + dst_buf = src_buffer; + + /* set Y plane */ + for (i = 0; i < player->captured.height[0]; i++) { + memcpy(dst_buf, temp, width_align); + dst_buf += width_align; + temp += player->captured.stride_width[0]; + } + + temp = player->captured.data[1]; + + /* set UV plane*/ + for (j = 0; j < player->captured.height[1]; j++) { + memcpy(dst_buf, temp, width_align); + dst_buf += width_align; + temp += player->captured.stride_width[0]; + } + + /* free captured buf */ + MMPLAYER_FREEIF(player->captured.data[0]); + MMPLAYER_FREEIF(player->captured.data[1]); + + /* NV12 -> RGB888 */ + ret = __mm_player_convert_colorspace(player, (unsigned char*)src_buffer, MM_UTIL_IMG_FMT_NV12, + width_align, player->captured.height[0], MM_UTIL_IMG_FMT_RGB888); + if (ret != MM_ERROR_NONE) + { + debug_error("failed to convert nv12 linear"); + goto ERROR; + } + + } + + ret = _mmplayer_get_video_rotate_angle ((MMHandleType)player, &orientation); + if (ret != MM_ERROR_NONE) + { + debug_error("failed to get rotation angle"); + goto ERROR; + } + + debug_log ("orientation value = %d", orientation); + + ret = __mmplayer_handle_orientation (player, orientation, MM_UTIL_IMG_FMT_RGB888); + if (ret != MM_ERROR_NONE) + { + debug_error("failed to convert nv12 linear"); + goto ERROR; + } + + player->capture.fmt = MM_PLAYER_COLORSPACE_RGB888; + msg.data = &player->capture; + msg.size = player->capture.size; +// msg.captured_frame.width = player->capture.width; +// msg.captured_frame.height = player->capture.height; +// msg.captured_frame.orientation = player->capture.orientation; + + if (player->cmd >= MMPLAYER_COMMAND_START) + { + MMPLAYER_POST_MSG( player, MM_MESSAGE_VIDEO_CAPTURED, &msg ); + debug_log("returned from capture message callback"); + } + + g_mutex_unlock(&player->capture_thread_mutex); + + //MMPLAYER_FREEIF(player->capture.data); + continue; +ERROR: + if (player->video_cs == MM_PLAYER_COLORSPACE_NV12_TILED) + { + /* clean */ + MMPLAYER_FREEIF(linear_y_plane); + MMPLAYER_FREEIF(linear_uv_plane); + MMPLAYER_FREEIF(player->captured.data[0]); + MMPLAYER_FREEIF(player->captured.data[1]); + } + + msg.union_type = MM_MSG_UNION_CODE; + + g_mutex_unlock(&player->capture_thread_mutex); + MMPLAYER_POST_MSG( player, MM_MESSAGE_VIDEO_NOT_CAPTURED, &msg ); + } + return NULL; +EXIT: + g_mutex_unlock(&player->capture_thread_mutex); + return NULL; +} + +/** + * The output is fixed as RGB888 + */ +static int +__mmplayer_get_video_frame_from_buffer(mm_player_t* player, GstPad *pad, GstBuffer *buffer) +{ + gint yplane_size = 0; + gint uvplane_size = 0; + gint src_width = 0; + gint src_height = 0; + GstCaps *caps = NULL; + GstStructure *structure = NULL; + GstMapInfo mapinfo = GST_MAP_INFO_INIT; + GstMemory *memory = NULL; + mm_util_img_format src_fmt = MM_UTIL_IMG_FMT_YUV420; + mm_util_img_format dst_fmt = MM_UTIL_IMG_FMT_RGB888; // fixed + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + return_val_if_fail ( buffer, MM_ERROR_INVALID_ARGUMENT ); + + /* get fourcc */ + caps = gst_pad_get_current_caps(pad); + + return_val_if_fail ( caps, MM_ERROR_INVALID_ARGUMENT ); + MMPLAYER_LOG_GST_CAPS_TYPE(caps); + + structure = gst_caps_get_structure (caps, 0); + + return_val_if_fail (structure != NULL, MM_ERROR_PLAYER_INTERNAL); + + /* init capture image buffer */ + memset(&player->capture, 0x00, sizeof(MMPlayerVideoCapture)); + + gst_structure_get_int (structure, "width", &src_width); + gst_structure_get_int (structure, "height", &src_height); + + /* check rgb or yuv */ + if (gst_structure_has_name(structure, "video/x-raw")) + { + /* NV12T */ + const gchar *gst_format = gst_structure_get_string(structure, "format"); + if(!g_strcmp0(gst_format, "ST12") || !g_strcmp0(gst_format, "SN12")) + { + guint n; + debug_msg ("captured format is %s\n", gst_format); + + MMVideoBuffer *proved = NULL; + if(!g_strcmp0(gst_format, "ST12")) + player->video_cs = MM_PLAYER_COLORSPACE_NV12_TILED; + else + player->video_cs = MM_PLAYER_COLORSPACE_NV12; + + /* get video frame info from proved buffer */ + n = gst_buffer_n_memory(buffer); + memory = gst_buffer_peek_memory(buffer, n-1); + gst_memory_map(memory, &mapinfo, GST_MAP_READ); + proved = (MMVideoBuffer *)mapinfo.data; + + if ( !proved || !proved->data[0] || !proved->data[1] ) { + debug_error("fail to gst_memory_map"); + return MM_ERROR_PLAYER_INTERNAL; + } + +#if 0 + yplane_size = proved->size[0]; + uvplane_size = proved->size[1]; +#else + yplane_size = proved->stride_width[0] * proved->stride_height[0]; + uvplane_size = proved->stride_width[1] * proved->stride_height[1]; +#endif + + debug_msg ("yplane_size=%d, uvplane_size=%d\n", yplane_size, uvplane_size); + memset(&player->captured, 0x00, sizeof(MMVideoBuffer)); + memcpy(&player->captured, proved, sizeof(MMVideoBuffer)); + + player->captured.data[0] = g_try_malloc(yplane_size); + if ( !player->captured.data[0] ) { + gst_memory_unmap(memory, &mapinfo); + return MM_ERROR_SOUND_NO_FREE_SPACE; + } + + player->captured.data[1] = g_try_malloc(uvplane_size); + if ( !player->captured.data[1] ) { + gst_memory_unmap(memory, &mapinfo); + return MM_ERROR_SOUND_NO_FREE_SPACE; + } + + memcpy(player->captured.data[0], proved->data[0], yplane_size); + memcpy(player->captured.data[1], proved->data[1], uvplane_size); + + gst_memory_unmap(memory, &mapinfo); + + goto DONE; + } + else + { + GstVideoInfo format_info; + gst_video_info_from_caps(&format_info, caps); + + switch(GST_VIDEO_INFO_FORMAT(&format_info)) + { + case GST_VIDEO_FORMAT_I420: + src_fmt = MM_UTIL_IMG_FMT_I420; + break; + case GST_VIDEO_FORMAT_BGRA: + src_fmt = MM_UTIL_IMG_FMT_BGRA8888; + break; + case GST_VIDEO_FORMAT_BGRx: + src_fmt = MM_UTIL_IMG_FMT_BGRX8888; + break; + default: + goto UNKNOWN; + break; + } + } + } + else + { + goto UNKNOWN; + } + + gst_buffer_map(buffer, &mapinfo, GST_MAP_READ); + __mm_player_convert_colorspace(player, mapinfo.data, src_fmt, src_width, src_height, dst_fmt); + gst_buffer_unmap(buffer, &mapinfo); + +DONE: + /* do convert colorspace */ + g_cond_signal( &player->capture_thread_cond ); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; + +UNKNOWN: + debug_error("unknown format to capture\n"); + return MM_ERROR_PLAYER_INTERNAL; +} + +static GstPadProbeReturn +__mmplayer_video_capture_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data) +{ + mm_player_t* player = (mm_player_t*) u_data; + GstBuffer *buffer = NULL; + int ret = MM_ERROR_NONE; + + return_val_if_fail (info->data, GST_PAD_PROBE_REMOVE); + MMPLAYER_FENTER(); + + buffer = gst_pad_probe_info_get_buffer(info); + ret = __mmplayer_get_video_frame_from_buffer(player, pad, buffer); + + if ( ret != MM_ERROR_NONE) + { + debug_error("failed to get video frame"); + return GST_PAD_PROBE_REMOVE; + } + + /* remove probe to be called at one time */ + if (player->video_capture_cb_probe_id) + { + gst_pad_remove_probe(pad, player->video_capture_cb_probe_id); + player->video_capture_cb_probe_id = 0; + } + + MMPLAYER_FLEAVE(); + + return GST_PAD_PROBE_OK; +} + +static int +__mm_player_convert_colorspace(mm_player_t* player, unsigned char* src_data, mm_util_img_format src_fmt, unsigned int src_w, unsigned int src_h, mm_util_img_format dst_fmt) +{ + unsigned char *dst_data = NULL; + unsigned int dst_size; + int ret = MM_ERROR_NONE; + + return_val_if_fail(player, MM_ERROR_PLAYER_INTERNAL); + ret = mm_util_get_image_size(dst_fmt, src_w, src_h, &dst_size); + + if (ret != MM_ERROR_NONE) + { + debug_error("failed to get image size for capture, %d\n", ret); + return MM_ERROR_PLAYER_INTERNAL; + } + + secure_debug_log("width: %d, height: %d to capture, dest size: %d\n", src_w, src_h, dst_size); + + dst_data = (unsigned char*)g_malloc0(dst_size); + + if (!dst_data) + { + debug_error("no free space to capture\n"); + return MM_ERROR_PLAYER_NO_FREE_SPACE; + } + + ret = mm_util_convert_colorspace(src_data, src_w, src_h, src_fmt, dst_data, dst_fmt); + + if (ret != MM_ERROR_NONE) + { + debug_error("failed to convert for capture, %d\n", ret); + return MM_ERROR_PLAYER_INTERNAL; + } + + player->capture.size = dst_size; + player->capture.data = dst_data; + + return MM_ERROR_NONE; +} + +/* + * Get tiled address of position(x,y) + * + * @param x_size + * width of tiled[in] + * + * @param y_size + * height of tiled[in] + * + * @param x_pos + * x position of tield[in] + * + * @param src_size + * y position of tield[in] + * + * @return + * address of tiled data + */ +static int +__tile_4x2_read(int x_size, int y_size, int x_pos, int y_pos) +{ + int pixel_x_m1, pixel_y_m1; + int roundup_x; + int linear_addr0, linear_addr1, bank_addr ; + int x_addr; + int trans_addr; + + pixel_x_m1 = x_size -1; + pixel_y_m1 = y_size -1; + + roundup_x = ((pixel_x_m1 >> 7) + 1); + + x_addr = x_pos >> 2; + + if ((y_size <= y_pos+32) && ( y_pos < y_size) && + (((pixel_y_m1 >> 5) & 0x1) == 0) && (((y_pos >> 5) & 0x1) == 0)) { + linear_addr0 = (((y_pos & 0x1f) <<4) | (x_addr & 0xf)); + linear_addr1 = (((y_pos >> 6) & 0xff) * roundup_x + ((x_addr >> 6) & 0x3f)); + + if (((x_addr >> 5) & 0x1) == ((y_pos >> 5) & 0x1)) + bank_addr = ((x_addr >> 4) & 0x1); + else + bank_addr = 0x2 | ((x_addr >> 4) & 0x1); + } else { + linear_addr0 = (((y_pos & 0x1f) << 4) | (x_addr & 0xf)); + linear_addr1 = (((y_pos >> 6) & 0xff) * roundup_x + ((x_addr >> 5) & 0x7f)); + + if (((x_addr >> 5) & 0x1) == ((y_pos >> 5) & 0x1)) + bank_addr = ((x_addr >> 4) & 0x1); + else + bank_addr = 0x2 | ((x_addr >> 4) & 0x1); + } + + linear_addr0 = linear_addr0 << 2; + trans_addr = (linear_addr1 <<13) | (bank_addr << 11) | linear_addr0; + + return trans_addr; +} + +/* + * Converts tiled data to linear + * Crops left, top, right, buttom + * 1. Y of NV12T to Y of YUV420P + * 2. Y of NV12T to Y of YUV420S + * 3. UV of NV12T to UV of YUV420S + * + * @param yuv420_dest + * Y or UV plane address of YUV420[out] + * + * @param nv12t_src + * Y or UV plane address of NV12T[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_height + * Y: Height of YUV420, UV: Height/2 of YUV420[in] + * + * @param left + * Crop size of left + * + * @param top + * Crop size of top + * + * @param right + * Crop size of right + * + * @param buttom + * Crop size of buttom + */ +static void +__csc_tiled_to_linear_crop(unsigned char *yuv420_dest, unsigned char *nv12t_src, int yuv420_width, int yuv420_height, + int left, int top, int right, int buttom) +{ + int i, j; + int tiled_offset = 0, tiled_offset1 = 0; + int linear_offset = 0; + int temp1 = 0, temp2 = 0, temp3 = 0, temp4 = 0; + + temp3 = yuv420_width-right; + temp1 = temp3-left; + /* real width is greater than or equal 256 */ + if (temp1 >= 256) { + for (i=top; i>8)<<8; + temp3 = temp3>>6; + temp4 = i>>5; + if (temp4 & 0x1) { + /* odd fomula: 2+x+(x>>2)<<2+x_block_num*(y-1) */ + tiled_offset = temp4-1; + temp1 = ((yuv420_width+127)>>7)<<7; + tiled_offset = tiled_offset*(temp1>>6); + tiled_offset = tiled_offset+temp3; + tiled_offset = tiled_offset+2; + temp1 = (temp3>>2)<<2; + tiled_offset = tiled_offset+temp1; + tiled_offset = tiled_offset<<11; + tiled_offset1 = tiled_offset+2048*2; + temp4 = 8; + } else { + temp2 = ((yuv420_height+31)>>5)<<5; + if ((i+32)>2)<<2+x_block_num*y */ + temp1 = temp3+2; + temp1 = (temp1>>2)<<2; + tiled_offset = temp3+temp1; + temp1 = ((yuv420_width+127)>>7)<<7; + tiled_offset = tiled_offset+temp4*(temp1>>6); + tiled_offset = tiled_offset<<11; + tiled_offset1 = tiled_offset+2048*6; + temp4 = 8; + } else { + /* even2 fomula: x+x_block_num*y */ + temp1 = ((yuv420_width+127)>>7)<<7; + tiled_offset = temp4*(temp1>>6); + tiled_offset = tiled_offset+temp3; + tiled_offset = tiled_offset<<11; + tiled_offset1 = tiled_offset+2048*2; + temp4 = 4; + } + } + + temp1 = i&0x1F; + tiled_offset = tiled_offset+64*(temp1); + tiled_offset1 = tiled_offset1+64*(temp1); + temp2 = yuv420_width-left-right; + linear_offset = temp2*(i-top); + temp3 = ((j+256)>>8)<<8; + temp3 = temp3-j; + temp1 = left&0x3F; + if (temp3 > 192) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset+temp1, 64-temp1); + temp2 = ((left+63)>>6)<<6; + temp3 = ((yuv420_width-right)>>6)<<6; + if (temp2 == temp3) { + temp2 = yuv420_width-right-(64-temp1); + } + memcpy(yuv420_dest+linear_offset+64-temp1, nv12t_src+tiled_offset+2048, 64); + memcpy(yuv420_dest+linear_offset+128-temp1, nv12t_src+tiled_offset1, 64); + memcpy(yuv420_dest+linear_offset+192-temp1, nv12t_src+tiled_offset1+2048, 64); + linear_offset = linear_offset+256-temp1; + } else if (temp3 > 128) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset+2048+temp1, 64-temp1); + memcpy(yuv420_dest+linear_offset+64-temp1, nv12t_src+tiled_offset1, 64); + memcpy(yuv420_dest+linear_offset+128-temp1, nv12t_src+tiled_offset1+2048, 64); + linear_offset = linear_offset+192-temp1; + } else if (temp3 > 64) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset1+temp1, 64-temp1); + memcpy(yuv420_dest+linear_offset+64-temp1, nv12t_src+tiled_offset1+2048, 64); + linear_offset = linear_offset+128-temp1; + } else if (temp3 > 0) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset1+2048+temp1, 64-temp1); + linear_offset = linear_offset+64-temp1; + } + + tiled_offset = tiled_offset+temp4*2048; + j = (left>>8)<<8; + j = j + 256; + temp2 = yuv420_width-right-256; + for (; j<=temp2; j=j+256) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); + tiled_offset1 = tiled_offset1+temp4*2048; + memcpy(yuv420_dest+linear_offset+64, nv12t_src+tiled_offset+2048, 64); + memcpy(yuv420_dest+linear_offset+128, nv12t_src+tiled_offset1, 64); + tiled_offset = tiled_offset+temp4*2048; + memcpy(yuv420_dest+linear_offset+192, nv12t_src+tiled_offset1+2048, 64); + linear_offset = linear_offset+256; + } + + tiled_offset1 = tiled_offset1+temp4*2048; + temp2 = yuv420_width-right-j; + if (temp2 > 192) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); + memcpy(yuv420_dest+linear_offset+64, nv12t_src+tiled_offset+2048, 64); + memcpy(yuv420_dest+linear_offset+128, nv12t_src+tiled_offset1, 64); + memcpy(yuv420_dest+linear_offset+192, nv12t_src+tiled_offset1+2048, temp2-192); + } else if (temp2 > 128) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); + memcpy(yuv420_dest+linear_offset+64, nv12t_src+tiled_offset+2048, 64); + memcpy(yuv420_dest+linear_offset+128, nv12t_src+tiled_offset1, temp2-128); + } else if (temp2 > 64) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); + memcpy(yuv420_dest+linear_offset+64, nv12t_src+tiled_offset+2048, temp2-64); + } else { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, temp2); + } + } + } else if (temp1 >= 64) { + for (i=top; i<(yuv420_height-buttom); i=i+1) { + j = left; + tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i); + temp2 = ((j+64)>>6)<<6; + temp2 = temp2-j; + linear_offset = temp1*(i-top); + temp4 = j&0x3; + tiled_offset = tiled_offset+temp4; + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, temp2); + linear_offset = linear_offset+temp2; + j = j+temp2; + if ((j+64) <= temp3) { + tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i); + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); + linear_offset = linear_offset+64; + j = j+64; + } + if ((j+64) <= temp3) { + tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i); + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); + linear_offset = linear_offset+64; + j = j+64; + } + if (j < temp3) { + tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i); + temp2 = temp3-j; + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, temp2); + } + } + } else { + for (i=top; i<(yuv420_height-buttom); i=i+1) { + linear_offset = temp1*(i-top); + for (j=left; j<(yuv420_width-right); j=j+2) { + tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i); + temp4 = j&0x3; + tiled_offset = tiled_offset+temp4; + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 2); + linear_offset = linear_offset+2; + } + } + } +} diff --git a/src/server/mm_player_es.c b/src/server/mm_player_es.c new file mode 100644 index 0000000..21efc6c --- /dev/null +++ b/src/server/mm_player_es.c @@ -0,0 +1,717 @@ +/* + * libmm-player + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , heechul jeon , + * YoungHwan An , Eunhae Choi + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*=========================================================================================== +| | +| INCLUDE FILES | +| | +========================================================================================== */ +#include "mm_player_es.h" +#include "mm_player_utils.h" +#include "mm_player_internal.h" + +#include + +/*--------------------------------------------------------------------------- +| LOCAL VARIABLE DEFINITIONS for internal | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| LOCAL FUNCTION PROTOTYPES: | +---------------------------------------------------------------------------*/ +static int _parse_media_format (MMPlayerVideoStreamInfo * video, MMPlayerAudioStreamInfo * audio, media_format_h format); +static int _convert_media_format_video_mime_to_str (MMPlayerVideoStreamInfo * video, media_format_mimetype_e mime); +static int _convert_media_format_audio_mime_to_str (MMPlayerAudioStreamInfo * audio, media_format_mimetype_e mime); + +/*=========================================================================================== +| | +| FUNCTION DEFINITIONS | +| | +========================================================================================== */ + +static int +_convert_media_format_video_mime_to_str (MMPlayerVideoStreamInfo * video, + media_format_mimetype_e mime) +{ + return_val_if_fail (video, MM_ERROR_INVALID_ARGUMENT); + + switch (mime) { + case MEDIA_FORMAT_MPEG4_SP: + video->mime = g_strdup ("video/mpeg"); + video->version = 4; + break; + case MEDIA_FORMAT_H264_SP: + case MEDIA_FORMAT_H264_MP: + case MEDIA_FORMAT_H264_HP: + video->mime = g_strdup ("video/x-h264"); + break; + default: + video->mime = g_strdup ("unknown"); + break; + } + + return MM_ERROR_NONE; +} + +static int +_convert_media_format_audio_mime_to_str (MMPlayerAudioStreamInfo * audio, + media_format_mimetype_e mime) +{ + return_val_if_fail (audio, MM_ERROR_INVALID_ARGUMENT); + + switch (mime) { + case MEDIA_FORMAT_AAC: + audio->mime = g_strdup ("audio/mpeg"); + audio->version = 2; + break; + default: + audio->mime = g_strdup ("unknown"); + break; + } + + return MM_ERROR_NONE; +} + +static int +_parse_media_format (MMPlayerVideoStreamInfo * video, + MMPlayerAudioStreamInfo * audio, media_format_h format) +{ + if (audio) { + media_format_mimetype_e mime; + int channel; + int samplerate; + int avg_bps; + + if (media_format_get_audio_info (format, &mime, &channel, &samplerate, NULL, + &avg_bps) != MEDIA_FORMAT_ERROR_NONE) { + debug_error ("media_format_get_audio_info failed"); + return MM_ERROR_PLAYER_INTERNAL; + } + + _convert_media_format_audio_mime_to_str (audio, mime); + audio->sample_rate = samplerate; + audio->channels = channel; +//video->user_info = ; + } + + if (video) { + media_format_mimetype_e mime; + int width; + int height; + int avg_bps; + + if (media_format_get_video_info (format, &mime, &width, &height, &avg_bps, + NULL) != MEDIA_FORMAT_ERROR_NONE) { + debug_error ("media_format_get_video_info failed"); + return MM_ERROR_PLAYER_INTERNAL; + } + + _convert_media_format_video_mime_to_str (video, mime); + video->width = width; + video->height = height; + } + + return MM_ERROR_NONE; +} + +static gboolean +_mmplayer_update_video_info(MMHandleType hplayer, media_format_h fmt) +{ + mm_player_t *player = (mm_player_t *) hplayer; + gboolean ret = FALSE; + GstStructure *str = NULL; + media_format_mimetype_e mimetype = 0; + gint cur_width = 0, width = 0; + gint cur_height = 0, height = 0; + + MMPLAYER_FENTER (); + + return_val_if_fail (player, FALSE); + return_val_if_fail (fmt, FALSE); + + if (player->v_stream_caps) + { + str = gst_caps_get_structure (player->v_stream_caps, 0); + if ( !gst_structure_get_int (str, "width", &cur_width)) + { + debug_log ("missing 'width' field in video caps"); + } + + if ( !gst_structure_get_int (str, "height", &cur_height)) + { + debug_log ("missing 'height' field in video caps"); + } + + media_format_get_video_info(fmt, &mimetype, &width, &height, NULL, NULL); + if ((cur_width != width) || (cur_height != height)) + { + debug_warning ("resolution is changed %dx%d -> %dx%d", + cur_width, cur_height, width, height); + _mmplayer_set_video_info(hplayer, fmt); + ret = TRUE; + } + } + + MMPLAYER_FLEAVE (); + return ret; +} + + +int +_mmplayer_set_media_stream_buffer_status_cb(MMHandleType hplayer, + MMPlayerStreamType type, + mm_player_media_stream_buffer_status_callback callback, + void *user_param) +{ + mm_player_t *player = (mm_player_t *) hplayer; + + MMPLAYER_FENTER (); + + return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + if ((type < MM_PLAYER_STREAM_TYPE_DEFAULT) || (type > MM_PLAYER_STREAM_TYPE_TEXT)) + return MM_ERROR_INVALID_ARGUMENT; + + if (player->media_stream_buffer_status_cb[type]) + { + if (!callback) + { + debug_log ("[type:%d] will be clear.\n", type); + } + else + { + debug_log ("[type:%d] will be overwritten.\n", type); + } + } + + player->media_stream_buffer_status_cb[type] = callback; + player->buffer_cb_user_param = user_param; + + debug_log ("player handle %p, type %d, callback %p\n", player, type, + player->media_stream_buffer_status_cb[type]); + + MMPLAYER_FLEAVE (); + + return MM_ERROR_NONE; +} + +int +_mmplayer_set_media_stream_seek_data_cb(MMHandleType hplayer, + MMPlayerStreamType type, + mm_player_media_stream_seek_data_callback callback, + void *user_param) +{ + mm_player_t *player = (mm_player_t *) hplayer; + + MMPLAYER_FENTER (); + + return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + if ((type < MM_PLAYER_STREAM_TYPE_DEFAULT) || (type > MM_PLAYER_STREAM_TYPE_TEXT)) + return MM_ERROR_INVALID_ARGUMENT; + + if (player->media_stream_seek_data_cb[type]) + { + if (!callback) + { + debug_log ("[type:%d] will be clear.\n", type); + } + else + { + debug_log ("[type:%d] will be overwritten.\n", type); + } + } + + player->media_stream_seek_data_cb[type] = callback; + player->buffer_cb_user_param = user_param; + + debug_log ("player handle %p, type %d, callback %p\n", player, type, + player->media_stream_seek_data_cb[type]); + + MMPLAYER_FLEAVE (); + + return MM_ERROR_NONE; +} + +int +_mmplayer_set_media_stream_max_size(MMHandleType hplayer, MMPlayerStreamType type, guint64 max_size) +{ + mm_player_t *player = (mm_player_t *) hplayer; + + MMPLAYER_FENTER (); + + return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + if ((type < MM_PLAYER_STREAM_TYPE_DEFAULT) || (type > MM_PLAYER_STREAM_TYPE_TEXT)) + return MM_ERROR_INVALID_ARGUMENT; + + player->media_stream_buffer_max_size[type] = max_size; + + debug_log ("type %d, max_size %llu\n", + type, player->media_stream_buffer_max_size[type]); + + MMPLAYER_FLEAVE (); + + return MM_ERROR_NONE; +} + +int +_mmplayer_get_media_stream_max_size(MMHandleType hplayer, MMPlayerStreamType type, guint64 *max_size) +{ + mm_player_t *player = (mm_player_t *) hplayer; + + MMPLAYER_FENTER (); + + return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail (max_size, MM_ERROR_INVALID_ARGUMENT); + + if ((type < MM_PLAYER_STREAM_TYPE_DEFAULT) || (type > MM_PLAYER_STREAM_TYPE_TEXT)) + return MM_ERROR_INVALID_ARGUMENT; + + *max_size = player->media_stream_buffer_max_size[type]; + + MMPLAYER_FLEAVE (); + + return MM_ERROR_NONE; +} + +int +_mmplayer_set_media_stream_min_percent(MMHandleType hplayer, MMPlayerStreamType type, guint min_percent) +{ + mm_player_t *player = (mm_player_t *) hplayer; + + MMPLAYER_FENTER (); + + return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + if ((type < MM_PLAYER_STREAM_TYPE_DEFAULT) || (type > MM_PLAYER_STREAM_TYPE_TEXT)) + return MM_ERROR_INVALID_ARGUMENT; + + player->media_stream_buffer_min_percent[type] = min_percent; + + debug_log ("type %d, min_per %u\n", + type, player->media_stream_buffer_min_percent[type]); + + MMPLAYER_FLEAVE (); + + return MM_ERROR_NONE; +} + +int +_mmplayer_get_media_stream_min_percent(MMHandleType hplayer, MMPlayerStreamType type, guint *min_percent) +{ + mm_player_t *player = (mm_player_t *) hplayer; + + MMPLAYER_FENTER (); + + return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail (min_percent, MM_ERROR_INVALID_ARGUMENT); + + if ((type < MM_PLAYER_STREAM_TYPE_DEFAULT) || (type > MM_PLAYER_STREAM_TYPE_TEXT)) + return MM_ERROR_INVALID_ARGUMENT; + + *min_percent = player->media_stream_buffer_min_percent[type]; + + MMPLAYER_FLEAVE (); + + return MM_ERROR_NONE; +} + +int +_mmplayer_submit_packet (MMHandleType hplayer, media_packet_h packet) +{ + int ret = MM_ERROR_NONE; + GstBuffer *_buffer = NULL; + mm_player_t *player = (mm_player_t *) hplayer; + guint8 *buf = NULL; + MMPlayerTrackType streamtype = MM_PLAYER_TRACK_TYPE_AUDIO; + media_format_h fmt = NULL; + bool flag = FALSE; + + return_val_if_fail (packet, MM_ERROR_INVALID_ARGUMENT); + return_val_if_fail ( player && + player->pipeline && + player->pipeline->mainbin && + player->pipeline->mainbin[MMPLAYER_M_SRC].gst, + MM_ERROR_PLAYER_INTERNAL ); + + /* get stream type if audio or video */ + media_packet_is_audio (packet, &flag); + if (flag) { + streamtype = MM_PLAYER_TRACK_TYPE_AUDIO; + } else { + media_packet_is_video (packet, &flag); + + if (flag) + streamtype = MM_PLAYER_TRACK_TYPE_VIDEO; + else + streamtype = MM_PLAYER_TRACK_TYPE_TEXT; + } + + /* get data */ + media_packet_get_buffer_data_ptr (packet, (void **) &buf); + + if (buf != NULL) { + GstMapInfo buff_info = GST_MAP_INFO_INIT; + uint64_t size = 0; + uint64_t pts = 0; + + /* get size */ + media_packet_get_buffer_size (packet, &size); + + _buffer = gst_buffer_new_and_alloc (size); + if (!_buffer) { + debug_error("failed to allocate memory for push buffer\n"); + return MM_ERROR_PLAYER_NO_FREE_SPACE; + } + + if (gst_buffer_map (_buffer, &buff_info, GST_MAP_READWRITE)) { + + memcpy (buff_info.data, buf, size); + buff_info.size = size; + + gst_buffer_unmap (_buffer, &buff_info); + } + + /* get pts */ + media_packet_get_pts (packet, &pts); + GST_BUFFER_PTS (_buffer) = (GstClockTime) (pts * 1000000); + + if (streamtype == MM_PLAYER_TRACK_TYPE_AUDIO) { +#if 0 // TO CHECK : has gone (set to pad) + if (GST_CAPS_IS_SIMPLE (player->a_stream_caps)) + GST_BUFFER_CAPS (_buffer) = gst_caps_copy (player->a_stream_caps); + else + debug_error ("External Demuxer case: Audio Buffer Caps not set."); +#endif + if (player->pipeline->mainbin[MMPLAYER_M_2ND_SRC].gst) + gst_app_src_push_buffer (GST_APP_SRC (player->pipeline->mainbin[MMPLAYER_M_2ND_SRC].gst), _buffer); + else if (g_strrstr (GST_ELEMENT_NAME (player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "audio_appsrc")) + gst_app_src_push_buffer (GST_APP_SRC (player->pipeline->mainbin[MMPLAYER_M_SRC].gst), _buffer); + } else if (streamtype == MM_PLAYER_TRACK_TYPE_VIDEO) { +#if 0 // TO CHECK : has gone (set to pad) + if (GST_CAPS_IS_SIMPLE (player->v_stream_caps)) + GST_BUFFER_CAPS (_buffer) = gst_caps_copy (player->v_stream_caps); + else + debug_error ("External Demuxer case: Video Buffer Caps not set."); +#endif + /* get format to check video format */ + media_packet_get_format (packet, &fmt); + if (fmt) + { + gboolean ret = FALSE; + ret = _mmplayer_update_video_info(hplayer, fmt); + if (ret) + { + g_object_set(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), + "caps", player->v_stream_caps, NULL); + } + } + + gst_app_src_push_buffer (GST_APP_SRC (player->pipeline->mainbin[MMPLAYER_M_SRC].gst), _buffer); + } else if (streamtype == MM_PLAYER_TRACK_TYPE_TEXT) { +#if 0 // TO CHECK : has gone (set to pad) + if (GST_CAPS_IS_SIMPLE (player->s_stream_caps)) + GST_BUFFER_CAPS (_buffer) = gst_caps_copy (player->s_stream_caps); + else + debug_error ("External Demuxer case: Subtitle Buffer Caps not set."); +#endif + gst_app_src_push_buffer (GST_APP_SRC (player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst), _buffer); + } else { + debug_error ("Not a valid packet from external demux"); + return FALSE; + } + } else { + debug_log ("Sending EOS on pipeline..."); + if (streamtype == MM_PLAYER_TRACK_TYPE_AUDIO) { + if (player->pipeline->mainbin[MMPLAYER_M_2ND_SRC].gst) + g_signal_emit_by_name (player->pipeline-> + mainbin[MMPLAYER_M_2ND_SRC].gst, "end-of-stream", &ret); + else + g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, + "end-of-stream", &ret); + } else if (streamtype == MM_PLAYER_TRACK_TYPE_VIDEO) { + g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, + "end-of-stream", &ret); + } else if (streamtype == MM_PLAYER_TRACK_TYPE_TEXT) { + g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst, + "end-of-stream", &ret); + } + } + + if (MMPLAYER_PENDING_STATE (player) == MM_PLAYER_STATE_PLAYING) { + //ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING); + } + + return ret; +} + +int +_mmplayer_video_caps_new (MMHandleType hplayer, MMPlayerVideoStreamInfo * video, + const char *fieldname, ...) +{ + int cap_size; + GstCaps *caps = NULL; + GstStructure *structure = NULL; + va_list var_args; + mm_player_t *player = MM_PLAYER_CAST (hplayer); + + MMPLAYER_FENTER (); + return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail (video, MM_ERROR_PLAYER_NOT_INITIALIZED); + + debug_log ("width=%d height=%d framerate num=%d, den=%d", + video->width, video->height, video->framerate_num, video->framerate_den); + + caps = gst_caps_new_simple (video->mime, + "width", G_TYPE_INT, video->width, + "height", G_TYPE_INT, video->height, + "framerate", GST_TYPE_FRACTION, video->framerate_num, video->framerate_den, NULL); + + for (cap_size = 0; cap_size < gst_caps_get_size (caps); cap_size++) { + va_start (var_args, fieldname); + structure = gst_caps_get_structure (caps, cap_size); + gst_structure_set_valist (structure, fieldname, var_args); + va_end (var_args); + } + + if (video->extradata_size) { + GstBuffer *buf = NULL; + GstMapInfo buff_info = GST_MAP_INFO_INIT; + + buf = gst_buffer_new_and_alloc (video->extradata_size); + + if (gst_buffer_map (buf, &buff_info, GST_MAP_READ)) { + memcpy (buff_info.data, video->codec_extradata, video->extradata_size); + buff_info.size = video->extradata_size; + gst_buffer_unmap (buf, &buff_info); + } + + gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, buf, NULL); + gst_buffer_unref (buf); + } + + if (player->v_stream_caps) + { + debug_warning ("caps will be updated "); + + gst_caps_unref(player->v_stream_caps); + player->v_stream_caps = NULL; + } + + player->v_stream_caps = gst_caps_copy (caps); + MMPLAYER_LOG_GST_CAPS_TYPE (player->v_stream_caps); + gst_caps_unref (caps); + + MMPLAYER_FLEAVE (); + + return MM_ERROR_NONE; +} + +int +_mmplayer_set_video_info (MMHandleType hplayer, media_format_h format) +{ + mm_player_t *player = MM_PLAYER_CAST (hplayer); + MMPlayerVideoStreamInfo video = { 0, }; + int ret = MM_ERROR_NONE; + + MMPLAYER_FENTER (); + + return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + ret = _parse_media_format (&video, NULL, format); + if(ret != MM_ERROR_NONE) + return ret; + + if (strstr (video.mime, "video/mpeg")) { + _mmplayer_video_caps_new (hplayer, &video, + "mpegversion", G_TYPE_INT, video.version, + "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); + } else if (strstr (video.mime, "video/x-h264")) { + //if (info.colordepth) + { + // _mmplayer_video_caps_new(hplayer, &info, + // "colordepth", G_TYPE_INT, info.colordepth, NULL); + } + //else + { + _mmplayer_video_caps_new (hplayer, &video, + "stream-format", G_TYPE_STRING, "byte-stream", + "alignment", G_TYPE_STRING, "au", NULL); + } + } +#if 0 + else if (strstr (info->mime, "video/x-wmv")) { + _mmplayer_video_caps_new (hplayer, &info, + "wmvversion", G_TYPE_INT, info.version, NULL); + } else if (strstr (info.mime, "video/x-pn-realvideo")) { + _mmplayer_video_caps_new (hplayer, &info, + "rmversion", G_TYPE_INT, info.version, NULL); + } else if (strstr (info.mime, "video/x-msmpeg")) { + _mmplayer_video_caps_new (hplayer, &info, + "msmpegversion", G_TYPE_INT, info.version, NULL); + } else if (strstr (info.mime, "video/x-h265")) { + if (info.colordepth) { + _mmplayer_video_caps_new (hplayer, &info, + "colordepth", G_TYPE_INT, info.colordepth, NULL); + } else { + _mmplayer_video_caps_new (hplayer, &info, NULL); + } + } else { + _mmplayer_video_caps_new (hplayer, &info, NULL); + } +#endif + g_free ((char *) video.mime); + + MMPLAYER_FLEAVE (); + + return MM_ERROR_NONE; +} + +int +_mmplayer_set_audio_info (MMHandleType hplayer, media_format_h format) +{ + mm_player_t *player = MM_PLAYER_CAST (hplayer); + GstCaps *caps = NULL; + MMPlayerAudioStreamInfo audio = { 0, }; + int ret = MM_ERROR_NONE; + + MMPLAYER_FENTER (); + + return_val_if_fail (hplayer, MM_ERROR_PLAYER_NOT_INITIALIZED); + + ret = _parse_media_format (NULL, &audio, format); + if(ret != MM_ERROR_NONE) + return ret; + + audio.user_info = 0; //test + + debug_log ("set audio player[%p] info [%p] version=%d rate=%d channel=%d", + player, audio, audio.version, audio.sample_rate, audio.channels); + + if (strstr (audio.mime, "audio/mpeg")) { + if (audio.version == 1) { // mp3 + caps = gst_caps_new_simple ("audio/mpeg", + "channels", G_TYPE_INT, audio.channels, + "rate", G_TYPE_INT, audio.sample_rate, + "mpegversion", G_TYPE_INT, audio.version, + "layer", G_TYPE_INT, audio.user_info, NULL); + } else { // aac + gchar *format = NULL; + + if (audio.user_info == 0) + format = g_strdup ("raw"); + else if (audio.user_info == 1) + format = g_strdup ("adts"); + else if (audio.user_info == 2) + format = g_strdup ("adif"); + + caps = gst_caps_new_simple ("audio/mpeg", + "channels", G_TYPE_INT, audio.channels, + "rate", G_TYPE_INT, audio.sample_rate, + "mpegversion", G_TYPE_INT, audio.version, + "stream-format", G_TYPE_STRING, format, NULL); + + g_free (format); + format = NULL; + } + } +#if 0 + else if (strstr (audio.mime, "audio/x-raw-int")) { + caps = gst_caps_new_simple ("audio/x-raw-int", + "width", G_TYPE_INT, audio.width, + "depth", G_TYPE_INT, audio.depth, + "endianness", G_TYPE_INT, audio.endianness, + "signed", G_TYPE_BOOLEAN, audio.signedness, + "channels", G_TYPE_INT, audio.channels, + "rate", G_TYPE_INT, audio.sample_rate, NULL); + } else { + caps = gst_caps_new_simple (audio.mime, + "channels", G_TYPE_INT, audio.channels, + "rate", G_TYPE_INT, audio.sample_rate, NULL); + } +#endif + + if (audio.extradata_size) { + GstBuffer *buf = NULL; + GstMapInfo buff_info = GST_MAP_INFO_INIT; + + buf = gst_buffer_new_and_alloc (audio.extradata_size); + + if (gst_buffer_map (buf, &buff_info, GST_MAP_READ)) { + memcpy (buff_info.data, audio.codec_extradata, audio.extradata_size); + gst_buffer_unmap (buf, &buff_info); + } + + gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, buf, NULL); + gst_buffer_unref (buf); + } + + g_free ((char *) audio.mime); + + player->a_stream_caps = gst_caps_copy (caps); + gst_caps_unref (caps); + + MMPLAYER_FLEAVE (); + + return MM_ERROR_NONE; +} + +int +_mmplayer_set_subtitle_info (MMHandleType hplayer, + MMPlayerSubtitleStreamInfo * subtitle) +{ +#if 0 //todo + + mm_player_t *player = MM_PLAYER_CAST (hplayer); + GstCaps *caps = NULL; + + MMPLAYER_FENTER (); + + return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail (info, MM_ERROR_PLAYER_NOT_INITIALIZED); + + debug_log ("set subtitle player[%p] info [%p]", player, info); + + + caps = gst_caps_new_simple (info->mime, NULL, NULL); // TO CHECK + if (NULL == caps) + return FALSE; + + if (strstr (info->mime, "application/x-xsub")) { + gst_caps_set_simple (caps, "codec_tag", G_TYPE_UINT, info->codec_tag, NULL); + } else if (strstr (info->mime, "application/x-smpte-text")) { + if (info->context) { + gst_caps_set_simple (caps, "ttml_priv_data", G_TYPE_POINTER, + info->context, NULL); + } + } + + player->s_stream_caps = gst_caps_copy (caps); + + gst_caps_unref (caps); +#endif + + MMPLAYER_FLEAVE (); + + return MM_ERROR_NONE; +} diff --git a/src/server/mm_player_pd.c b/src/server/mm_player_pd.c new file mode 100644 index 0000000..09f16cc --- /dev/null +++ b/src/server/mm_player_pd.c @@ -0,0 +1,467 @@ +/* + * libmm-player + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , naveen cherukuri , + * YeJin Cho , YoungHwan An + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include +#include +#include "mm_player_pd.h" +#include "mm_player_utils.h" +#include "mm_player_priv.h" + +/*--------------------------------------------------------------------------------------- +| LOCAL FUNCTION PROTOTYPES: | +---------------------------------------------------------------------------------------*/ + +/* It's callback to process whenever there is some changes in PD downloader. */ +static gboolean __pd_downloader_callback(GstBus *bus, GstMessage *msg, gpointer data); + +/* This function posts messages to application. */ +/* Currently, MM_MESSAGE_PD_DOWNLOADER_START and MM_MESSAGE_PD_DOWNLOADER_END are used. */ +static gboolean __pd_downloader_post_message(mm_player_t * player, enum MMMessageType msgtype, MMMessageParamType* param); + +/*======================================================================================= +| FUNCTION DEFINITIONS | +=======================================================================================*/ +static gboolean +__pd_downloader_callback(GstBus *bus, GstMessage *msg, gpointer data) +{ + mm_player_t * player = NULL; + mm_player_pd_t *pd = NULL; + gboolean bret = TRUE; + + MMPLAYER_FENTER(); + + /* chech player handle */ + return_val_if_fail ( data, MM_ERROR_INVALID_ARGUMENT ); + + player = MM_PLAYER_CAST((MMHandleType)data); + + /* get PD downloader handle */ + pd = MM_PLAYER_GET_PD((MMHandleType)data); + + return_val_if_fail ( pd, MM_ERROR_INVALID_ARGUMENT ); + +// g_print("%s\n", GST_MESSAGE_TYPE_NAME(msg)); + + switch ( GST_MESSAGE_TYPE( msg ) ) + { + case GST_MESSAGE_EOS: + { + debug_log("PD Downloader EOS received....\n"); + + g_object_set (G_OBJECT (pd->playback_pipeline_src), "eos", TRUE, NULL); + + /* notify application that download is completed */ + __pd_downloader_post_message(player, MM_MESSAGE_PD_DOWNLOADER_END, NULL); + + #ifdef PD_SELF_DOWNLOAD + _mmplayer_unrealize_pd_downloader ((MMHandleType)data); + #endif + } + break; + + case GST_MESSAGE_ERROR: + { + GError *error = NULL; + gchar* debug = NULL; + GstMessage *new_msg = NULL; + + /* get error code */ + gst_message_parse_error( msg, &error, &debug ); + debug_error ("GST_MESSAGE_ERROR = %s\n", debug); + + new_msg = gst_message_new_error (GST_OBJECT_CAST (pd->playback_pipeline_src), error, debug); + + /* notify application that pd has any error */ + gst_element_post_message (pd->playback_pipeline_src, new_msg); + + _mmplayer_unrealize_pd_downloader ((MMHandleType)data); + MMPLAYER_FREEIF(debug); + g_error_free( error); + } + break; + + case GST_MESSAGE_WARNING: + { + char* debug = NULL; + GError* error = NULL; + + gst_message_parse_warning(msg, &error, &debug); + debug_warning("warning : %s\n", error->message); + debug_warning("debug : %s\n", debug); + + MMPLAYER_FREEIF(debug); + g_error_free( error); + } + break; + + case GST_MESSAGE_STATE_CHANGED: + { + GstState old_state, new_state; + gchar *src_name; + + /* get old and new state */ + gst_message_parse_state_changed (msg, &old_state, &new_state, NULL); + + if (old_state == new_state) + break; + + /* we only care about pipeline state changes */ + if (GST_MESSAGE_SRC (msg) != GST_OBJECT (pd->downloader_pipeline)) + break; + + src_name = gst_object_get_name (msg->src); + debug_log ("%s changed state from %s to %s", src_name, + gst_element_state_get_name (old_state), + gst_element_state_get_name (new_state)); + g_free (src_name); + + switch(new_state) + { + case GST_STATE_VOID_PENDING: + case GST_STATE_NULL: + case GST_STATE_READY: + case GST_STATE_PAUSED: + break; + + case GST_STATE_PLAYING: + /* notify application that download is stated */ + __pd_downloader_post_message(player, MM_MESSAGE_PD_DOWNLOADER_START, NULL); + break; + + default: + break; + } + } + break; + + case GST_MESSAGE_DURATION: + { + gint64 size = 0LL; + + /* get total size of download file, (bytes) */ + if ( ! gst_element_query_duration( pd->downloader_pipeline, GST_FORMAT_BYTES, &size ) ) + { + GError *err = NULL; + GstMessage *new_msg = NULL; + + err = g_error_new (GST_STREAM_ERROR, GST_STREAM_ERROR_FAILED, "can't get total size"); + new_msg = gst_message_new_error (GST_OBJECT_CAST (pd->playback_pipeline_src), err, NULL); + gst_element_post_message (pd->playback_pipeline_src, new_msg); + + g_error_free (err); + + // TODO: check if playback pipeline is closed well or not + g_object_set (G_OBJECT (pd->playback_pipeline_src), "eos", TRUE, NULL); + + _mmplayer_unrealize_pd_downloader ((MMHandleType)data); + + debug_error("failed to query total size for download\n"); + break; + } + + pd->total_size = size; + + debug_log("PD total size : %lld bytes\n", size); + } + break; + + default: + debug_warning("unhandled message\n"); + break; + } + + MMPLAYER_FLEAVE(); + + return bret; +} + + +gboolean __pd_downloader_post_message(mm_player_t * player, enum MMMessageType msgtype, MMMessageParamType* param) +{ + MMPLAYER_FENTER(); + + return_val_if_fail( player, FALSE ); + + if ( !player->pd_msg_cb ) + { + debug_warning("no msg callback. can't post\n"); + return FALSE; + } + + player->pd_msg_cb(msgtype, param, player->pd_msg_cb_param); + + MMPLAYER_FLEAVE(); + + return TRUE; +} + + +gboolean _mmplayer_get_pd_downloader_status(MMHandleType handle, guint64 *current_pos, guint64 *total_size) +{ + MMPLAYER_FENTER(); + + mm_player_pd_t * pd = NULL; + guint64 bytes = 0; + + return_val_if_fail(handle, MM_ERROR_INVALID_ARGUMENT); + + pd = MM_PLAYER_GET_PD(handle); + + return_val_if_fail(pd, MM_ERROR_INVALID_ARGUMENT); + return_val_if_fail(pd->downloader_pipeline, MM_ERROR_PLAYER_INVALID_STATE); + + if ( !pd->total_size ) + { + debug_warning("not ready to get total size\n"); + return FALSE; + } + + g_object_get(pd->downloader_sink, "current-bytes", &bytes, NULL); + + debug_log("PD status : %lld / %lld\n", bytes, pd->total_size); + + *current_pos = bytes; + *total_size = pd->total_size; + + MMPLAYER_FLEAVE(); + + return TRUE; +} + + +mm_player_pd_t * _mmplayer_create_pd_downloader() +{ + MMPLAYER_FENTER(); + + mm_player_pd_t * pd = NULL; + + /* create PD handle */ + pd = (mm_player_pd_t *) malloc (sizeof (mm_player_pd_t)); + if ( !pd ) + { + debug_error ("Failed to create pd downloader handle...\n"); + return FALSE; + } + memset( pd, 0, sizeof (mm_player_pd_t)); + + MMPLAYER_FLEAVE(); + + return pd; +} + + +gboolean _mmplayer_destroy_pd_downloader (MMHandleType handle) +{ + MMPLAYER_FENTER(); + + mm_player_pd_t * pd = NULL; + + return_val_if_fail ( handle, MM_ERROR_INVALID_ARGUMENT ); + + pd = MM_PLAYER_GET_PD(handle); + + if (pd && pd->downloader_pipeline) + _mmplayer_unrealize_pd_downloader (handle); + + /* release PD handle */ + MMPLAYER_FREEIF(pd); + + MMPLAYER_FLEAVE(); + + return TRUE; +} + + +gboolean _mmplayer_realize_pd_downloader (MMHandleType handle, gchar *src_uri, gchar *dst_uri, GstElement *pushsrc) +{ + MMPLAYER_FENTER(); + + mm_player_pd_t * pd = NULL; + + return_val_if_fail ( handle, MM_ERROR_INVALID_ARGUMENT ); + return_val_if_fail ( src_uri, MM_ERROR_INVALID_ARGUMENT ); + return_val_if_fail ( dst_uri, MM_ERROR_INVALID_ARGUMENT ); + return_val_if_fail ( pushsrc, MM_ERROR_INVALID_ARGUMENT ); + + pd = MM_PLAYER_GET_PD(handle); + + /* initialize */ + pd->path_read_from = g_strdup (src_uri); + pd->location_to_save = g_strdup (dst_uri); + pd->playback_pipeline_src = pushsrc; + pd->total_size = 0LL; + + MMPLAYER_FLEAVE(); + + return TRUE; +} + + +gboolean _mmplayer_start_pd_downloader (MMHandleType handle) +{ + GstBus* bus = NULL; + gboolean bret = FALSE; + GstStateChangeReturn sret = GST_STATE_CHANGE_SUCCESS; + GstState cur_state; + GstState pending_state; + + MMPLAYER_FENTER(); + + mm_player_pd_t * pd = NULL; + + return_val_if_fail ( handle, MM_ERROR_INVALID_ARGUMENT ); + + pd = MM_PLAYER_GET_PD(handle); + + /* pipeline */ + pd->downloader_pipeline = gst_pipeline_new ("PD Downloader"); + if (NULL == pd->downloader_pipeline) + { + debug_error ("Can't create PD download pipeline..."); + return FALSE; + } + + /* source */ + pd->downloader_src = gst_element_factory_make ("souphttpsrc", "PD HTTP download source"); + if (NULL == pd->downloader_src) + { + debug_error ("Can't create PD download src..."); + return FALSE; + } + + /* queue */ + pd->downloader_queue = gst_element_factory_make ("queue", "PD download queue"); + if (NULL == pd->downloader_queue) + { + debug_error ("Can't create PD download queue..."); + return FALSE; + } + + /* filesink */ + pd->downloader_sink = gst_element_factory_make ("filesink", "PD download sink"); + if (NULL == pd->downloader_sink) + { + debug_error ("Can't create PD download sink..."); + return FALSE; + } + + g_object_set(pd->downloader_sink, "sync", FALSE, NULL); + + /* Add to bin and link */ + gst_bin_add_many (GST_BIN (pd->downloader_pipeline), + pd->downloader_src, pd->downloader_queue, pd->downloader_sink, + NULL); + + bret = gst_element_link_many (pd->downloader_src, pd->downloader_queue, pd->downloader_sink, NULL); + if (FALSE == bret) + { + debug_error ("Can't link elements src and sink..."); + return FALSE; + } + + /* Get Bus and set callback to watch */ + bus = gst_pipeline_get_bus (GST_PIPELINE (pd->downloader_pipeline)); + gst_bus_add_watch (bus, __pd_downloader_callback, (gpointer)handle); + gst_object_unref (bus); + + /* Set URI on HTTP source */ + g_object_set (G_OBJECT (pd->downloader_src), "location", pd->path_read_from, NULL); + + /* set file download location on filesink*/ + g_object_set (G_OBJECT (pd->downloader_sink), "location", pd->location_to_save, NULL); + + secure_debug_log ("src location = %s, save location = %s\n", pd->path_read_from, pd->location_to_save); + + /* Start to download */ + sret = gst_element_set_state (pd->downloader_pipeline, GST_STATE_PLAYING); + if (GST_STATE_CHANGE_FAILURE == sret) + { + debug_error ("PD download pipeline failed to go to PLAYING state..."); + return FALSE; + } + + debug_log ("set_state :: sret = %d\n", sret); + + sret = gst_element_get_state (pd->downloader_pipeline, &cur_state, &pending_state, GST_CLOCK_TIME_NONE); + if (GST_STATE_CHANGE_FAILURE == sret) + { + debug_error ("PD download pipeline failed to do get_state..."); + return FALSE; + } + + debug_log ("get-state :: sret = %d\n", sret); + + MMPLAYER_FLEAVE(); + + return TRUE; +} + + +gboolean _mmplayer_unrealize_pd_downloader (MMHandleType handle) +{ + MMPLAYER_FENTER(); + + mm_player_pd_t * pd = NULL; + + return_val_if_fail ( handle, FALSE ); + + pd = MM_PLAYER_GET_PD(handle); + + return_val_if_fail ( pd && pd->downloader_pipeline, FALSE ); + + gst_element_set_state (pd->downloader_pipeline, GST_STATE_NULL); + gst_element_get_state (pd->downloader_pipeline, NULL, NULL, GST_CLOCK_TIME_NONE); + + gst_object_unref (G_OBJECT (pd->downloader_pipeline)); + pd->downloader_pipeline = NULL; + + /* free */ + MMPLAYER_FREEIF(pd->path_read_from); + MMPLAYER_FREEIF(pd->location_to_save); + + MMPLAYER_FLEAVE(); + + return TRUE; +} + + +gint _mm_player_set_pd_downloader_message_cb(MMHandleType handle, MMMessageCallback callback, gpointer user_param) +{ + MMPLAYER_FENTER(); + + mm_player_t * player = NULL; + + return_val_if_fail ( handle, MM_ERROR_INVALID_ARGUMENT ); + + player = MM_PLAYER_CAST((MMHandleType)handle); + + /* PD callback can be set as soon as player handle is created. + * So, player handle must have it. + */ + player->pd_msg_cb = callback; + player->pd_msg_cb_param = user_param; + + debug_log("msg_cb : %p msg_cb_param : %p\n", callback, user_param); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} diff --git a/src/server/mm_player_priv.c b/src/server/mm_player_priv.c new file mode 100644 index 0000000..6577858 --- /dev/null +++ b/src/server/mm_player_priv.c @@ -0,0 +1,16721 @@ +/* + * libmm-player + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , YeJin Cho , + * Seungbae Shin , YoungHwan An + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*=========================================================================================== +| | +| INCLUDE FILES | +| | +========================================================================================== */ +#include +#include +#include +#include +#ifdef HAVE_WAYLAND +#include +#endif +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "mm_player_priv.h" +#include "mm_player_ini.h" +#include "mm_player_attrs.h" +#include "mm_player_capture.h" +#include "mm_player_utils.h" +#include "mm_player_tracks.h" +#include + +#include +#include + +#define MM_SMOOTH_STREAMING + +/*=========================================================================================== +| | +| LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE | +| | +========================================================================================== */ + +/*--------------------------------------------------------------------------- +| GLOBAL CONSTANT DEFINITIONS: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| IMPORTED VARIABLE DECLARATIONS: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| IMPORTED FUNCTION DECLARATIONS: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| LOCAL #defines: | +---------------------------------------------------------------------------*/ +#define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0 +#define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0 + +#define MM_VOLUME_FACTOR_DEFAULT 1.0 +#define MM_VOLUME_FACTOR_MIN 0 +#define MM_VOLUME_FACTOR_MAX 1.0 + +#define MM_PLAYER_FADEOUT_TIME_DEFAULT 700000 // 700 msec + +#define MM_PLAYER_MPEG_VNAME "mpegversion" +#define MM_PLAYER_DIVX_VNAME "divxversion" +#define MM_PLAYER_WMV_VNAME "wmvversion" +#define MM_PLAYER_WMA_VNAME "wmaversion" + +#define DEFAULT_PLAYBACK_RATE 1.0 +#define PLAYBACK_RATE_EX_AUDIO_MIN 0.5 +#define PLAYBACK_RATE_EX_AUDIO_MAX 2.0 +#define PLAYBACK_RATE_EX_VIDEO_MIN 0.5 +#define PLAYBACK_RATE_EX_VIDEO_MAX 1.5 + +#define GST_QUEUE_DEFAULT_TIME 4 +#define GST_QUEUE_HLS_TIME 8 + +#define DEFAULT_AUDIO_CH 0 + +#define MMPLAYER_USE_FILE_FOR_BUFFERING(player) (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && (player->ini.http_file_buffer_path) && (strlen(player->ini.http_file_buffer_path) > 0) ) + +#define LAZY_PAUSE_TIMEOUT_MSEC 700 +#define MM_PLAYER_NAME "mmplayer" + +#define SMOOTH_STREAMING_DEMUX "mssdemux" +/* + * g_array_index(a,t,i) does not calculate gst private structure. + * It replaces the g_array_index(a,t,i) + */ +#define g_array_undef_struct_idx_p(a,t,i) ((t *)(void *)((a)->data + ((i) * (a)->len))) + +//#define ENABLE_DRMSRC + +/*--------------------------------------------------------------------------- +| LOCAL CONSTANT DEFINITIONS: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| LOCAL DATA TYPE DEFINITIONS: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| GLOBAL VARIABLE DEFINITIONS: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| LOCAL VARIABLE DEFINITIONS: | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| LOCAL FUNCTION PROTOTYPES: | +---------------------------------------------------------------------------*/ +static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type); +static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player); +static int __mmplayer_gst_create_text_pipeline(mm_player_t* player); +static int __mmplayer_gst_create_subtitle_src(mm_player_t* player); +static int __mmplayer_gst_create_pipeline(mm_player_t* player); +static int __mmplayer_gst_destroy_pipeline(mm_player_t* player); +static int __mmplayer_gst_element_link_bucket(GList* element_bucket); + +static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data); +static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data); +static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data); +static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data); +static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data); +static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data); +static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data); +//static GValueArray* __mmplayer_gst_decode_autoplug_factories(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data); +static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data); +static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data); +static void __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data); +static GstElement * __mmplayer_create_decodebin(mm_player_t* player); +static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps); + +static void __mmplayer_typefind_have_type( GstElement *tf, guint probability, GstCaps *caps, gpointer data); +static gboolean __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps); +static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data); +static gboolean __mmplayer_is_midi_type(gchar* str_caps); +static gboolean __mmplayer_is_only_mp3_type (gchar *str_caps); +static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps); +//static void __mmplayer_check_video_zero_cpoy(mm_player_t* player, GstElementFactory* factory); + +static gboolean __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement, const char *padname, const GList *templlist); +static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data); +static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data); + +static void __mmplayer_gst_rtp_no_more_pads (GstElement *element, gpointer data); +//static void __mmplayer_gst_wfd_dynamic_pad (GstElement *element, GstPad *pad, gpointer data); +static void __mmplayer_gst_rtp_dynamic_pad (GstElement *element, GstPad *pad, gpointer data); +static gboolean __mmplayer_get_stream_service_type( mm_player_t* player ); +static gboolean __mmplayer_update_subtitle( GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data); + + +static void __mmplayer_init_factories(mm_player_t* player); +static void __mmplayer_release_factories(mm_player_t* player); +static void __mmplayer_release_misc(mm_player_t* player); +static void __mmplayer_release_misc_post(mm_player_t* player); +static gboolean __mmplayer_init_gstreamer(mm_player_t* player); +static GstBusSyncReply __mmplayer_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data); +static gboolean __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data); + +static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg); +static gboolean __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg); + +int __mmplayer_switch_audio_sink (mm_player_t* player); +static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink); +static GstPadProbeReturn __mmplayer_audio_stream_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data); +static GstPadProbeReturn __mmplayer_video_stream_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data); +static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data); +static int __mmplayer_change_selector_pad (mm_player_t* player, MMPlayerTrackType type, int index); + +static gboolean __mmplayer_check_subtitle( mm_player_t* player ); +static gboolean __mmplayer_handle_streaming_error ( mm_player_t* player, GstMessage * message ); +static void __mmplayer_handle_eos_delay( mm_player_t* player, int delay_in_ms ); +static void __mmplayer_cancel_eos_timer( mm_player_t* player ); +static gboolean __mmplayer_eos_timer_cb(gpointer u_data); +static gboolean __mmplayer_link_decoder( mm_player_t* player,GstPad *srcpad); +static gboolean __mmplayer_link_sink( mm_player_t* player,GstPad *srcpad); +static int __mmplayer_handle_missed_plugin(mm_player_t* player); +static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime); +static gboolean __mmplayer_configure_audio_callback(mm_player_t* player); +static void __mmplayer_add_sink( mm_player_t* player, GstElement* sink); +static void __mmplayer_del_sink( mm_player_t* player, GstElement* sink); +static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type); +static gpointer __mmplayer_next_play_thread(gpointer data); +static gpointer __mmplayer_repeat_thread(gpointer data); +static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag); + + +static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element); +static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data); +static void __mmplayer_release_dump_list (GList *dump_list); + +static int __gst_realize(mm_player_t* player); +static int __gst_unrealize(mm_player_t* player); +static int __gst_start(mm_player_t* player); +static int __gst_stop(mm_player_t* player); +static int __gst_pause(mm_player_t* player, gboolean async); +static int __gst_resume(mm_player_t* player, gboolean async); +static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate, + GstFormat format, GstSeekFlags flags, GstSeekType cur_type, + gint64 cur, GstSeekType stop_type, gint64 stop ); +static int __gst_pending_seek ( mm_player_t* player ); + +static int __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called); +static int __gst_get_position(mm_player_t* player, int format, unsigned long *position); +static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos); +static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position); +static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param); + +static gboolean __gst_send_event_to_sink( mm_player_t* player, GstEvent* event ); + +static int __mmplayer_set_pcm_extraction(mm_player_t* player); +static gboolean __mmplayer_can_extract_pcm( mm_player_t* player ); + +/*fadeout */ +static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time); +static void __mmplayer_undo_sound_fadedown(mm_player_t* player); + +static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data); +static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps); + +/* util */ +static gboolean __is_es_buff_src(mm_player_t* player); +static gboolean __has_suffix(mm_player_t * player, const gchar * suffix); + +static int __mmplayer_realize_streaming_ext(mm_player_t* player); +static int __mmplayer_unrealize_streaming_ext(mm_player_t *player); +static int __mmplayer_start_streaming_ext(mm_player_t *player); +static int __mmplayer_destroy_streaming_ext(mm_player_t* player); +static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay); + +static gboolean __mmplayer_verify_next_play_path(mm_player_t *player); +static void __mmplayer_activate_next_source(mm_player_t *player, GstState target); +static void __mmplayer_check_pipeline(mm_player_t* player); +static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type); +static void __mmplayer_deactivate_old_path(mm_player_t *player); +#if 0 // We'll need this in future. +static int __mmplayer_gst_switching_element(mm_player_t *player, GstElement *search_from, const gchar *removal_name, const gchar *new_element_name); +#endif + +static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg); +static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name); +static gboolean __mmplayer_can_do_interrupt(mm_player_t *player); + +/* device change post proc */ +void __mmplayer_device_change_post_process(gpointer user); +void __mmplayer_set_required_cb_score(mm_player_t* player, guint score); +void __mmplayer_inc_cb_score(mm_player_t* player); +void __mmplayer_post_proc_reset(mm_player_t* player); +void __mmplayer_device_change_trigger_post_process(mm_player_t* player); +static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player); +static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name); +static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data); +static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data); +static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data); +static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data); +static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data); +static gboolean __gst_seek_audio_data (GstElement * appsrc, guint64 position, gpointer user_data); +static gboolean __gst_seek_video_data (GstElement * appsrc, guint64 position, gpointer user_data); +static gboolean __gst_seek_subtitle_data (GstElement * appsrc, guint64 position, gpointer user_data); +/*=========================================================================================== +| | +| FUNCTION DEFINITIONS | +| | +========================================================================================== */ + +#if 0 //debug +static void +print_tag (const GstTagList * list, const gchar * tag, gpointer unused) +{ + gint i, count; + + count = gst_tag_list_get_tag_size (list, tag); + + debug_log("count = %d", count); + + for (i = 0; i < count; i++) { + gchar *str; + + if (gst_tag_get_type (tag) == G_TYPE_STRING) { + if (!gst_tag_list_get_string_index (list, tag, i, &str)) + g_assert_not_reached (); + } else { + str = + g_strdup_value_contents (gst_tag_list_get_value_index (list, tag, i)); + } + + if (i == 0) { + g_print (" %15s: %s\n", gst_tag_get_nick (tag), str); + } else { + g_print (" : %s\n", str); + } + + g_free (str); + } +} +#endif + +static void +__mmplayer_videostream_cb(GstElement *element, void *data, +int width, int height, gpointer user_data) // @ +{ + mm_player_t* player = (mm_player_t*)user_data; + + return_if_fail ( player ); + + MMPLAYER_FENTER(); + + if (player->is_drm_file) + { + MMMessageParamType msg_param = { 0, }; + debug_warning("not supported in drm file"); + msg_param.code = MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION; + MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param ); + } + else if ( !player->set_mode.media_packet_video_stream && player->video_stream_cb) + { + MMPlayerVideoStreamDataType stream; + + /* clear stream data structure */ + memset(&stream, 0x0, sizeof(MMPlayerVideoStreamDataType)); + + stream.data[0] = data; + stream.length_total = width * height * 4; // for rgb 32bit + stream.height = height; + stream.width = width; + player->video_stream_cb(&stream, player->video_stream_cb_user_param); + } + + MMPLAYER_FLEAVE(); +} + +static void +__mmplayer_videoframe_render_error_cb(GstElement *element, void *error_id, gpointer data) +{ + mm_player_t* player = (mm_player_t*)data; + + return_if_fail ( player ); + + MMPLAYER_FENTER(); + + if (player->video_frame_render_error_cb ) + { + if (player->attrs) + { + int surface_type = 0; + mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type); + switch (surface_type) + { + case MM_DISPLAY_SURFACE_X_EXT: + player->video_frame_render_error_cb((unsigned int*)error_id, player->video_frame_render_error_cb_user_param); + debug_log("display surface type(X_EXT) : render error callback(%p) is finished", player->video_frame_render_error_cb); + break; + default: + debug_error("video_frame_render_error_cb was set, but this surface type(%d) is not supported", surface_type); + break; + } + } + else + { + debug_error("could not get surface type"); + } + } + else + { + debug_warning("video_frame_render_error_cb was not set"); + } + + MMPLAYER_FLEAVE(); +} + +void +__mmplayer_device_change_post_process(gpointer user) +{ + mm_player_t* player = (mm_player_t*)user; + unsigned long position = 0; + MMPlayerStateType current_state = MM_PLAYER_STATE_NONE; + MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE; + + MMPLAYER_FENTER(); + + if (! player || + ! player->pipeline || + ! player->pipeline->mainbin || + ! player->pipeline->mainbin[MMPLAYER_M_PIPE].gst ) + { + goto EXIT; + } + + current_state = MMPLAYER_CURRENT_STATE(player); + pending_state = MMPLAYER_PENDING_STATE(player); + + if (player->post_proc.need_pause_and_resume) + { + debug_log("pausing"); + if ((pending_state == MM_PLAYER_STATE_PLAYING) || + ((pending_state == MM_PLAYER_STATE_NONE) && (current_state != MM_PLAYER_STATE_PAUSED))) + gst_element_set_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED); + } + + /* seek should be done within pause and resume */ + if (player->post_proc.need_seek) + { + debug_log("seeking"); + __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position); + debug_log(">> seek to current position = %ld ms", position); + __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE); + } + + if (player->post_proc.need_pause_and_resume) + { + debug_log("resuming"); + if ((pending_state == MM_PLAYER_STATE_PLAYING) || + ((pending_state == MM_PLAYER_STATE_NONE) && (current_state != MM_PLAYER_STATE_PAUSED))) + gst_element_set_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING); + } + + /* async */ + if (player->post_proc.need_async) + { + debug_log("setting async"); + + /* TODO : need some comment here */ + if (player->pipeline->textbin && player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst) + g_object_set (G_OBJECT (player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL); + } + +EXIT: + /* reset all */ + __mmplayer_post_proc_reset(player); + return; +} + +void __mmplayer_set_required_cb_score(mm_player_t* player, guint score) +{ + return_if_fail(player); + player->post_proc.required_cb_score = score; + debug_log("set required score to : %d", score); +} + +void __mmplayer_inc_cb_score(mm_player_t* player) +{ + return_if_fail(player); + player->post_proc.cb_score++; + debug_log("post proc cb score increased to %d", player->post_proc.cb_score); +} + +void __mmplayer_post_proc_reset(mm_player_t* player) +{ + return_if_fail(player); + + /* check if already triggered */ + if (player->post_proc.id) + { + /* TODO : need to consider multiple main context. !!!! */ + if (FALSE == g_source_remove(player->post_proc.id) ) + { + debug_error("failed to remove exist post_proc item"); + } + player->post_proc.id = 0; + } + + memset(&player->post_proc, 0, sizeof(mm_player_post_proc_t)); + + /* set default required cb score 1 as only audio device has changed in this case. + if display status is changed with audio device, required cb score is set 2 in display status callback. + this logic bases on the assumption which audio device callback is called after calling display status callback. */ + player->post_proc.required_cb_score = 1; +} + +void +__mmplayer_device_change_trigger_post_process(mm_player_t* player) +{ + return_if_fail(player); + + /* check score */ + if ( player->post_proc.cb_score < player->post_proc.required_cb_score ) + { + /* wait for next turn */ + debug_log("wait for next turn. required cb score : %d current score : %d\n", + player->post_proc.required_cb_score, player->post_proc.cb_score); + return; + } + + /* check if already triggered */ + if (player->post_proc.id) + { + /* TODO : need to consider multiple main context. !!!! */ + if (FALSE == g_source_remove(player->post_proc.id) ) + { + debug_error("failed to remove exist post_proc item"); + } + player->post_proc.id = 0; + } + + player->post_proc.id = g_idle_add((GSourceFunc)__mmplayer_device_change_post_process, (gpointer)player); +} +#if 0 +/* NOTE : Sound module has different latency according to output device So, + * synchronization problem can be happened whenever device is changed. + * To avoid this issue, we do reset avsystem or seek as workaroud. + */ +static void +__mmplayer_sound_device_info_changed_cb_func (MMSoundDevice_t device_h, int changed_info_type, void *user_data) +{ + int ret; + mm_sound_device_type_e device_type; + mm_player_t* player = (mm_player_t*) user_data; + + return_if_fail( player ); + + debug_warning("device_info_changed_cb is called, device_h[0x%x], changed_info_type[%d]\n", device_h, changed_info_type); + + __mmplayer_inc_cb_score(player); + + /* get device type with device_h*/ + ret = mm_sound_get_device_type(device_h, &device_type); + if (ret) { + debug_error("failed to mm_sound_get_device_type()\n"); + } + + /* do pause and resume only if video is playing */ + if ( player->videodec_linked && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING ) + { + switch (device_type) + { + case MM_SOUND_DEVICE_TYPE_BLUETOOTH: + case MM_SOUND_DEVICE_TYPE_AUDIOJACK: + case MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER: + case MM_SOUND_DEVICE_TYPE_HDMI: + case MM_SOUND_DEVICE_TYPE_MIRRORING: + { + player->post_proc.need_pause_and_resume = TRUE; + } + break; + + default: + debug_log("do nothing"); + } + } + debug_warning("dispatched"); + + __mmplayer_device_change_trigger_post_process(player); +} +#endif +/* This function should be called after the pipeline goes PAUSED or higher +state. */ +gboolean +_mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag) // @ +{ + static gboolean has_duration = FALSE; + static gboolean has_video_attrs = FALSE; + static gboolean has_audio_attrs = FALSE; + static gboolean has_bitrate = FALSE; + gboolean missing_only = FALSE; + gboolean all = FALSE; + gint64 dur_nsec = 0; + GstStructure* p = NULL; + MMHandleType attrs = 0; + gchar *path = NULL; + gint stream_service_type = STREAMING_SERVICE_NONE; + struct stat sb; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, FALSE ); + + /* check player state here */ + if ( MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED && + MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING ) + { + /* give warning now only */ + debug_warning("be careful. content attributes may not available in this state "); + } + + /* get content attribute first */ + attrs = MMPLAYER_GET_ATTRS(player); + if ( !attrs ) + { + debug_error("cannot get content attribute"); + return FALSE; + } + + /* get update flag */ + + if ( flag & ATTR_MISSING_ONLY ) + { + missing_only = TRUE; + debug_log("updating missed attr only"); + } + + if ( flag & ATTR_ALL ) + { + all = TRUE; + has_duration = FALSE; + has_video_attrs = FALSE; + has_audio_attrs = FALSE; + has_bitrate = FALSE; + + debug_log("updating all attrs"); + } + + if ( missing_only && all ) + { + debug_warning("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!"); + missing_only = FALSE; + } + + if ( (flag & ATTR_DURATION) || (!has_duration && missing_only) || all ) + { + debug_log("try to update duration"); + has_duration = FALSE; + + if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec )) + { + player->duration = dur_nsec; + debug_warning("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec)); + } + + /* try to get streaming service type */ + stream_service_type = __mmplayer_get_stream_service_type( player ); + mm_attrs_set_int_by_name ( attrs, "streaming_type", stream_service_type ); + + /* check duration is OK */ + if ( dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING( player ) ) + { + /* FIXIT : find another way to get duration here. */ + debug_error("finally it's failed to get duration from pipeline. progressbar will not work correctely!"); + } + else + { + /*update duration */ + mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec)); + has_duration = TRUE; + } + } + + if ( (flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all ) + { + /* update audio params + NOTE : We need original audio params and it can be only obtained from src pad of audio + decoder. Below code only valid when we are not using 'resampler' just before + 'audioconverter'. */ + + debug_log("try to update audio attrs"); + has_audio_attrs = FALSE; + + if ( player->pipeline->audiobin && + player->pipeline->audiobin[MMPLAYER_A_SINK].gst ) + { + GstCaps *caps_a = NULL; + GstPad* pad = NULL; + gint samplerate = 0, channels = 0; + + pad = gst_element_get_static_pad( + player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink" ); + + if ( pad ) + { + caps_a = gst_pad_get_current_caps( pad ); + + if ( caps_a ) + { + p = gst_caps_get_structure (caps_a, 0); + + mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate); + + gst_structure_get_int (p, "rate", &samplerate); + mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate); + + gst_structure_get_int (p, "channels", &channels); + mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels); + + secure_debug_log("samplerate : %d channels : %d", samplerate, channels); + + gst_caps_unref( caps_a ); + caps_a = NULL; + + has_audio_attrs = TRUE; + } + else + { + debug_warning("not ready to get audio caps"); + } + + gst_object_unref( pad ); + } + else + { + debug_warning("failed to get pad from audiosink"); + } + } + } + + if ( (flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all ) + { + debug_log("try to update video attrs"); + has_video_attrs = FALSE; + + if ( player->pipeline->videobin && + player->pipeline->videobin[MMPLAYER_V_SINK].gst ) + { + GstCaps *caps_v = NULL; + GstPad* pad = NULL; + gint tmpNu, tmpDe; + gint width, height; + + pad = gst_element_get_static_pad( player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink" ); + if ( pad ) + { + caps_v = gst_pad_get_current_caps( pad ); + + /* Use v_stream_caps, if fail to get video_sink sink pad*/ + if (!caps_v && player->v_stream_caps) + { + caps_v = player->v_stream_caps; + gst_caps_ref(caps_v); + } + + if (caps_v) + { + p = gst_caps_get_structure (caps_v, 0); + gst_structure_get_int (p, "width", &width); + mm_attrs_set_int_by_name(attrs, "content_video_width", width); + + gst_structure_get_int (p, "height", &height); + mm_attrs_set_int_by_name(attrs, "content_video_height", height); + + gst_structure_get_fraction (p, "framerate", &tmpNu, &tmpDe); + + secure_debug_log("width : %d height : %d", width, height ); + + gst_caps_unref( caps_v ); + caps_v = NULL; + + if (tmpDe > 0) + { + mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe); + secure_debug_log("fps : %d", tmpNu / tmpDe); + } + + has_video_attrs = TRUE; + } + else + { + debug_log("no negitiated caps from videosink"); + } + gst_object_unref( pad ); + pad = NULL; + } + else + { + debug_log("no videosink sink pad"); + } + } + } + + + if ( (flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all ) + { + has_bitrate = FALSE; + + /* FIXIT : please make it clear the dependancy with duration/codec/uritype */ + if (player->duration) + { + guint64 data_size = 0; + + if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) + { + mm_attrs_get_string_by_name(attrs, "profile_uri", &path); + + if (stat(path, &sb) == 0) + { + data_size = (guint64)sb.st_size; + } + } + else if (MMPLAYER_IS_HTTP_STREAMING(player)) + { + data_size = player->http_content_size; + } + debug_log("try to update bitrate : data_size = %lld", data_size); + + if (data_size) + { + guint64 bitrate = 0; + guint64 msec_dur = 0; + + msec_dur = GST_TIME_AS_MSECONDS(player->duration); + bitrate = data_size * 8 * 1000 / msec_dur; + secure_debug_log("file size : %u, video bitrate = %llu", data_size, bitrate); + mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate); + + has_bitrate = TRUE; + } + + if (MMPLAYER_IS_RTSP_STREAMING(player)) + { + if(player->total_bitrate) + { + mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate); + has_bitrate = TRUE; + } + } + } + } + + /* validate all */ + if ( mmf_attrs_commit ( attrs ) ) + { + debug_error("failed to update attributes\n"); + return FALSE; + } + + MMPLAYER_FLEAVE(); + + return TRUE; +} + +static gboolean __mmplayer_get_stream_service_type( mm_player_t* player ) +{ + gint streaming_type = STREAMING_SERVICE_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player && + player->pipeline && + player->pipeline->mainbin && + player->pipeline->mainbin[MMPLAYER_M_SRC].gst, + FALSE ); + + /* streaming service type if streaming */ + if ( ! MMPLAYER_IS_STREAMING(player) ) + return STREAMING_SERVICE_NONE; + + if (MMPLAYER_IS_HTTP_STREAMING(player)) + { + streaming_type = (player->duration == 0) ? + STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD; + } + + switch ( streaming_type ) + { + case STREAMING_SERVICE_LIVE: + debug_log("it's live streaming"); + break; + case STREAMING_SERVICE_VOD: + debug_log("it's vod streaming"); + break; + case STREAMING_SERVICE_NONE: + debug_error("should not get here"); + break; + default: + debug_error("should not get here"); + } + + player->streaming_type = streaming_type; + MMPLAYER_FLEAVE(); + + return streaming_type; +} + + +/* this function sets the player state and also report + * it to applicaton by calling callback function + */ +int +__mmplayer_set_state(mm_player_t* player, int state) // @ +{ + MMMessageParamType msg = {0, }; + int sound_result = MM_ERROR_NONE; + gboolean post_bos = FALSE; + gboolean interrupted_by_asm = FALSE; + int ret = MM_ERROR_NONE; + + return_val_if_fail ( player, FALSE ); + + if ( MMPLAYER_CURRENT_STATE(player) == state ) + { + debug_warning("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state)); + MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE; + return ret; + } + + /* update player states */ + MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player); + MMPLAYER_CURRENT_STATE(player) = state; + + /* FIXIT : it's better to do like below code + if ( MMPLAYER_CURRENT_STATE(player) == MMPLAYER_TARGET_STATE(player) ) + MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE; + and add more code to handling PENDING_STATE. + */ + if ( MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player) ) + MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE; + + /* print state */ + MMPLAYER_PRINT_STATE(player); + + /* do some FSM stuffs before posting new state to application */ + interrupted_by_asm = player->sound_focus.by_asm_cb; + + switch ( MMPLAYER_CURRENT_STATE(player) ) + { + case MM_PLAYER_STATE_NULL: + case MM_PLAYER_STATE_READY: + { + if (player->cmd == MMPLAYER_COMMAND_STOP) + { + sound_result = _mmplayer_sound_release_focus(&player->sound_focus); + if ( sound_result != MM_ERROR_NONE ) + { + debug_error("failed to release sound focus\n"); + return MM_ERROR_POLICY_INTERNAL; + } + } + } + break; + + case MM_PLAYER_STATE_PAUSED: + { + if ( ! player->sent_bos ) + { + int found = 0; + #define MMPLAYER_MAX_SOUND_PRIORITY 3 + + /* it's first time to update all content attrs. */ + _mmplayer_update_content_attrs( player, ATTR_ALL ); + /* set max sound priority to keep own sound and not to mute other's one */ + mm_attrs_get_int_by_name(player->attrs, "content_video_found", &found); + if (found) + { + mm_attrs_get_int_by_name(player->attrs, "content_audio_found", &found); + if (found) + { + debug_log("set max audio priority"); + g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "priority", MMPLAYER_MAX_SOUND_PRIORITY, NULL); + } + } + + } + + /* add audio callback probe if condition is satisfied */ + if ( ! player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex) + { + __mmplayer_configure_audio_callback(player); + /* FIXIT : handle return value */ + } + + if (!MMPLAYER_IS_STREAMING(player) || (player->streamer && !player->streamer->is_buffering)) + { + sound_result = _mmplayer_sound_release_focus(&player->sound_focus); + if ( sound_result != MM_ERROR_NONE ) + { + debug_error("failed to release sound focus\n"); + return MM_ERROR_POLICY_INTERNAL; + } + } + } + break; + + case MM_PLAYER_STATE_PLAYING: + { + /* try to get content metadata */ + if ( ! player->sent_bos ) + { + /* NOTE : giving ATTR_MISSING_ONLY may have dependency with + * c-api since c-api doesn't use _start() anymore. It may not work propery with + * legacy mmfw-player api */ + _mmplayer_update_content_attrs( player, ATTR_MISSING_ONLY); + } + + if ( (player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME) ) + { + if (!player->sent_bos) + { + __mmplayer_handle_missed_plugin ( player ); + } + sound_result = _mmplayer_sound_acquire_focus(&player->sound_focus); + if (sound_result != MM_ERROR_NONE) + { + // FIXME : need to check history + if (player->pipeline->videobin) + { + MMMessageParamType msg = {0, }; + + debug_error("failed to go ahead because of video conflict\n"); + + msg.union_type = MM_MSG_UNION_CODE; + msg.code = MM_ERROR_POLICY_INTERRUPTED; + MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg); + + _mmplayer_unrealize((MMHandleType)player); + } + else + { + debug_error("failed to play by sound focus error : 0x%X\n", sound_result); + _mmplayer_pause((MMHandleType)player); + return sound_result; + } + + return MM_ERROR_POLICY_INTERNAL; + } + } + + if ( player->resumed_by_rewind && player->playback_rate < 0.0 ) + { + /* initialize because auto resume is done well. */ + player->resumed_by_rewind = FALSE; + player->playback_rate = 1.0; + } + + if ( !player->sent_bos ) + { + /* check audio codec field is set or not + * we can get it from typefinder or codec's caps. + */ + gchar *audio_codec = NULL; + mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec); + + /* The codec format can't be sent for audio only case like amr, mid etc. + * Because, parser don't make related TAG. + * So, if it's not set yet, fill it with found data. + */ + if ( ! audio_codec ) + { + if ( g_strrstr(player->type, "audio/midi")) + { + audio_codec = g_strdup("MIDI"); + + } + else if ( g_strrstr(player->type, "audio/x-amr")) + { + audio_codec = g_strdup("AMR"); + } + else if ( g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion=(int)1")) + { + audio_codec = g_strdup("AAC"); + } + else + { + audio_codec = g_strdup("unknown"); + } + mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec); + + MMPLAYER_FREEIF(audio_codec); + mmf_attrs_commit(player->attrs); + debug_log("set audio codec type with caps\n"); + } + + post_bos = TRUE; + } + } + break; + + case MM_PLAYER_STATE_NONE: + default: + debug_warning("invalid target state, there is nothing to do.\n"); + break; + } + + + /* post message to application */ + if (MMPLAYER_TARGET_STATE(player) == state) + { + /* fill the message with state of player */ + msg.state.previous = MMPLAYER_PREV_STATE(player); + msg.state.current = MMPLAYER_CURRENT_STATE(player); + + debug_log ("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player))); + + /* state changed by asm callback */ + if ( interrupted_by_asm ) + { + msg.union_type = MM_MSG_UNION_CODE; + msg.code = player->sound_focus.focus_changed_msg; /* FIXME: player.c convert function have to be modified. */ + MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg ); + } + /* state changed by usecase */ + else + { + MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_CHANGED, &msg ); + } + } + else + { + debug_log ("intermediate state, do nothing.\n"); + MMPLAYER_PRINT_STATE(player); + return ret; + } + + if ( post_bos ) + { + MMPLAYER_POST_MSG ( player, MM_MESSAGE_BEGIN_OF_STREAM, NULL ); + player->sent_bos = TRUE; + } + + return ret; +} + +gboolean +__mmplayer_post_message(mm_player_t* player, enum MMMessageType msgtype, MMMessageParamType* param) // @ +{ + return_val_if_fail( player, FALSE ); + + if ( !player->msg_cb ) + { + return FALSE; + } + + //debug_log("Message (type : %d) will be posted using msg-cb(%p). \n", msgtype, player->msg_cb); + + player->msg_cb(msgtype, param, player->msg_cb_param); + + return TRUE; +} + +static gpointer __mmplayer_next_play_thread(gpointer data) +{ + mm_player_t* player = (mm_player_t*) data; + MMPlayerGstElement *mainbin = NULL; + + return_val_if_fail ( player, NULL ); + + g_mutex_lock(&player->next_play_thread_mutex); + while ( ! player->next_play_thread_exit ) + { + debug_log("next play thread started. waiting for signal.\n"); + g_cond_wait(&player->next_play_thread_cond, &player->next_play_thread_mutex ); + + debug_log("reconfigure pipeline for gapless play.\n"); + + if ( player->next_play_thread_exit ) + { + if(player->gapless.reconfigure) + { + player->gapless.reconfigure = false; + MMPLAYER_PLAYBACK_UNLOCK(player); + } + debug_log("exiting gapless play thread\n"); + break; + } + + mainbin = player->pipeline->mainbin; + + MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER); + MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX); + MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG); + MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND); + MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC); + + __mmplayer_activate_next_source(player, GST_STATE_PLAYING); + } + g_mutex_unlock(&player->next_play_thread_mutex); + + return NULL; +} + +static gpointer __mmplayer_repeat_thread(gpointer data) +{ + mm_player_t* player = (mm_player_t*) data; + gboolean ret_value = FALSE; + MMHandleType attrs = 0; + gint count = 0; + + return_val_if_fail ( player, NULL ); + + g_mutex_lock(&player->repeat_thread_mutex); + while ( ! player->repeat_thread_exit ) + { + debug_log("repeat thread started. waiting for signal.\n"); + g_cond_wait(&player->repeat_thread_cond, &player->repeat_thread_mutex ); + + if ( player->repeat_thread_exit ) + { + debug_log("exiting repeat thread\n"); + break; + } + + + /* lock */ + g_mutex_lock(&player->cmd_lock); + + attrs = MMPLAYER_GET_ATTRS(player); + + if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE) + { + debug_error("can not get play count\n"); + break; + } + + if ( player->section_repeat ) + { + ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end); + } + else + { + if ( player->playback_rate < 0.0 ) + { + player->resumed_by_rewind = TRUE; + _mmplayer_set_mute((MMHandleType)player, 0); + MMPLAYER_POST_MSG( player, MM_MESSAGE_RESUMED_BY_REW, NULL ); + } + + ret_value = __gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate, + GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, + 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); + + /* initialize */ + player->sent_bos = FALSE; + } + + if ( ! ret_value ) + { + debug_error("failed to set position to zero for rewind\n"); + continue; + } + + /* decrease play count */ + if ( count > 1 ) + { + /* we successeded to rewind. update play count and then wait for next EOS */ + count--; + + mm_attrs_set_int_by_name(attrs, "profile_play_count", count); + + /* commit attribute */ + if ( mmf_attrs_commit ( attrs ) ) + { + debug_error("failed to commit attribute\n"); + } + } + + /* unlock */ + g_mutex_unlock(&player->cmd_lock); + } + + g_mutex_unlock(&player->repeat_thread_mutex); + return NULL; +} + +static void +__mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg) +{ + MMHandleType attrs = 0; + guint64 data_size = 0; + gchar* path = NULL; + unsigned long pos_msec = 0; + struct stat sb; + + return_if_fail( player && player->pipeline && player->pipeline->mainbin); + + __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec); // update last_position + + attrs = MMPLAYER_GET_ATTRS(player); + if ( !attrs ) + { + debug_error("fail to get attributes.\n"); + return; + } + + if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) + { + mm_attrs_get_string_by_name(attrs, "profile_uri", &path); + + if (stat(path, &sb) == 0) + { + data_size = (guint64)sb.st_size; + } + } + else if (MMPLAYER_IS_HTTP_STREAMING(player)) + { + data_size = player->http_content_size; + } + + __mm_player_streaming_buffering( player->streamer, + buffering_msg, + data_size, + player->last_position, + player->duration); + + __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst); + + return; +} + + +static void +__mmplayer_handle_buffering_message ( mm_player_t* player ) +{ + MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE; + MMPlayerStateType current_state = MM_PLAYER_STATE_NONE; + MMPlayerStateType target_state = MM_PLAYER_STATE_NONE; + MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE; + + return_if_fail ( player ); + + prev_state = MMPLAYER_PREV_STATE(player); + current_state = MMPLAYER_CURRENT_STATE(player); + target_state = MMPLAYER_TARGET_STATE(player); + pending_state = MMPLAYER_PENDING_STATE(player); + + if (MMPLAYER_IS_LIVE_STREAMING(player)) + return; + + if ( !player->streamer->is_buffering ) + { + debug_log( "player state : prev %s, current %s, pending %s, target %s \n", + MMPLAYER_STATE_GET_NAME(prev_state), + MMPLAYER_STATE_GET_NAME(current_state), + MMPLAYER_STATE_GET_NAME(pending_state), + MMPLAYER_STATE_GET_NAME(target_state)); + + /* NOTE : if buffering has done, player has to go to target state. */ + switch ( target_state ) + { + case MM_PLAYER_STATE_PAUSED : + { + switch ( pending_state ) + { + case MM_PLAYER_STATE_PLAYING: + { + __gst_pause ( player, TRUE ); + } + break; + + case MM_PLAYER_STATE_PAUSED: + { + debug_log("player is already going to paused state, there is nothing to do.\n"); + } + break; + + case MM_PLAYER_STATE_NONE: + case MM_PLAYER_STATE_NULL: + case MM_PLAYER_STATE_READY: + default : + { + debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) ); + } + break; + } + } + break; + + case MM_PLAYER_STATE_PLAYING : + { + switch ( pending_state ) + { + case MM_PLAYER_STATE_NONE: + { + if (current_state != MM_PLAYER_STATE_PLAYING) + __gst_resume ( player, TRUE ); + } + break; + + case MM_PLAYER_STATE_PAUSED: + { + /* NOTE: It should be worked as asynchronously. + * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly. + */ + __gst_resume ( player, TRUE ); + } + break; + + case MM_PLAYER_STATE_PLAYING: + { + debug_log("player is already going to playing state, there is nothing to do.\n"); + } + break; + + case MM_PLAYER_STATE_NULL: + case MM_PLAYER_STATE_READY: + default : + { + debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) ); + } + break; + } + } + break; + + case MM_PLAYER_STATE_NULL : + case MM_PLAYER_STATE_READY : + case MM_PLAYER_STATE_NONE : + default: + { + debug_warning("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state) ); + } + break; + } + } + else + { + /* NOTE : during the buffering, pause the player for stopping pipeline clock. + * it's for stopping the pipeline clock to prevent dropping the data in sink element. + */ + switch ( pending_state ) + { + case MM_PLAYER_STATE_NONE: + { + if (current_state != MM_PLAYER_STATE_PAUSED) + { + debug_log("set pause state during buffering\n"); + __gst_pause ( player, TRUE ); + + // to cover the weak-signal environment. + if (MMPLAYER_IS_RTSP_STREAMING(player)) + { + unsigned long position = 0; + gint64 pos_msec = 0; + + debug_log("[RTSP] seek to the buffering start point\n"); + + if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position )) + { + debug_error("failed to get position\n"); + break; + } + + /* key unit seek */ + pos_msec = position * G_GINT64_CONSTANT(1000000); + + __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0, + GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, + pos_msec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); + } + } + } + break; + + case MM_PLAYER_STATE_PLAYING: + { + __gst_pause ( player, TRUE ); + } + break; + + case MM_PLAYER_STATE_PAUSED: + { + } + break; + + case MM_PLAYER_STATE_NULL: + case MM_PLAYER_STATE_READY: + default : + { + debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) ); + } + break; + } + } +} + +static void +__mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop) +{ + MMPlayerGstElement *textbin; + MMPLAYER_FENTER(); + + return_if_fail ( player && + player->pipeline && + player->pipeline->textbin); + + return_if_fail (player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst); + + textbin = player->pipeline->textbin; + + if (is_drop) + { + debug_log("Drop subtitle text after getting EOS\n"); + + g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL); + g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL); + + player->is_subtitle_force_drop = TRUE; + } + else + { + if (player->is_subtitle_force_drop == TRUE) + { + debug_log("Enable subtitle data path without drop\n"); + + g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL); + g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL); + + debug_log ("non-connected with external display"); + + player->is_subtitle_force_drop = FALSE; + } + } +} + +static gboolean +__mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @ +{ + mm_player_t* player = (mm_player_t*) data; + gboolean ret = TRUE; + static gboolean async_done = FALSE; + + return_val_if_fail ( player, FALSE ); + return_val_if_fail ( msg && GST_IS_MESSAGE(msg), FALSE ); + + switch ( GST_MESSAGE_TYPE( msg ) ) + { + case GST_MESSAGE_UNKNOWN: + debug_log("unknown message received\n"); + break; + + case GST_MESSAGE_EOS: + { + MMHandleType attrs = 0; + gint count = 0; + + debug_log("GST_MESSAGE_EOS received\n"); + + /* NOTE : EOS event is comming multiple time. watch out it */ + /* check state. we only process EOS when pipeline state goes to PLAYING */ + if ( ! (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) ) + { + debug_log("EOS received on non-playing state. ignoring it\n"); + break; + } + + __mmplayer_drop_subtitle(player, TRUE); + + if ( (player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) + { + GstPad *pad = NULL; + + pad = gst_element_get_static_pad (player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink"); + + debug_log("release audio callback\n"); + + /* release audio callback */ + gst_pad_remove_probe (pad, player->audio_cb_probe_id); + player->audio_cb_probe_id = 0; + /* audio callback should be free because it can be called even though probe remove.*/ + player->audio_stream_cb = NULL; + player->audio_stream_cb_user_param = NULL; + + } + + /* rewind if repeat count is greater then zero */ + /* get play count */ + attrs = MMPLAYER_GET_ATTRS(player); + + if ( attrs ) + { + gboolean smooth_repeat = FALSE; + + mm_attrs_get_int_by_name(attrs, "profile_play_count", &count); + mm_attrs_get_int_by_name(attrs, "profile_smooth_repeat", &smooth_repeat); + + player->play_count = count; + + debug_log("remaining play count: %d, playback rate: %f\n", count, player->playback_rate); + + if ( count > 1 || count == -1 || player->playback_rate < 0.0 ) /* default value is 1 */ + { + if ( smooth_repeat ) + { + debug_log("smooth repeat enabled. seeking operation will be excuted in new thread\n"); + + g_cond_signal( &player->repeat_thread_cond ); + + break; + } + else + { + gint ret_value = 0; + + if ( player->section_repeat ) + { + ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end); + } + else + { + if ( player->playback_rate < 0.0 ) + { + player->resumed_by_rewind = TRUE; + _mmplayer_set_mute((MMHandleType)player, 0); + MMPLAYER_POST_MSG( player, MM_MESSAGE_RESUMED_BY_REW, NULL ); + } + + __mmplayer_handle_eos_delay( player, player->ini.delay_before_repeat ); + + /* initialize */ + player->sent_bos = FALSE; + } + + if ( MM_ERROR_NONE != ret_value ) + { + debug_error("failed to set position to zero for rewind\n"); + } + + /* not posting eos when repeating */ + break; + } + } + } + + MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-eos" ); + + /* post eos message to application */ + __mmplayer_handle_eos_delay( player, player->ini.eos_delay ); + + /* reset last position */ + player->last_position = 0; + } + break; + + case GST_MESSAGE_ERROR: + { + GError *error = NULL; + gchar* debug = NULL; + + /* generating debug info before returning error */ + MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-error" ); + + /* get error code */ + gst_message_parse_error( msg, &error, &debug ); + + if ( gst_structure_has_name ( gst_message_get_structure(msg), "streaming_error" ) ) + { + /* Note : the streaming error from the streaming source is handled + * using __mmplayer_handle_streaming_error. + */ + __mmplayer_handle_streaming_error ( player, msg ); + + /* dump state of all element */ + __mmplayer_dump_pipeline_state( player ); + } + else + { + /* traslate gst error code to msl error code. then post it + * to application if needed + */ + __mmplayer_handle_gst_error( player, msg, error ); + + if (debug) + { + debug_error ("error debug : %s", debug); + } + + } + + if (MMPLAYER_IS_HTTP_PD(player)) + { + _mmplayer_unrealize_pd_downloader ((MMHandleType)player); + } + + MMPLAYER_FREEIF( debug ); + g_error_free( error ); + } + break; + + case GST_MESSAGE_WARNING: + { + char* debug = NULL; + GError* error = NULL; + + gst_message_parse_warning(msg, &error, &debug); + + debug_log("warning : %s\n", error->message); + debug_log("debug : %s\n", debug); + + MMPLAYER_POST_MSG( player, MM_MESSAGE_WARNING, NULL ); + + MMPLAYER_FREEIF( debug ); + g_error_free( error ); + } + break; + + case GST_MESSAGE_TAG: + { + debug_log("GST_MESSAGE_TAG\n"); + if ( ! __mmplayer_gst_extract_tag_from_msg( player, msg ) ) + { + debug_warning("failed to extract tags from gstmessage\n"); + } + } + break; + + case GST_MESSAGE_BUFFERING: + { + MMMessageParamType msg_param = {0, }; + + if (!MMPLAYER_IS_STREAMING(player)) + break; + + /* ignore the prev buffering message */ + if ((player->streamer) && (player->streamer->is_buffering == FALSE) && (player->streamer->is_buffering_done == TRUE)) + { + gint buffer_percent = 0; + + gst_message_parse_buffering (msg, &buffer_percent); + + if (buffer_percent == MAX_BUFFER_PERCENT) + { + debug_log ("Ignored all the previous buffering msg! (got %d%%)\n", buffer_percent); + player->streamer->is_buffering_done = FALSE; + } + + break; + } + + __mmplayer_update_buffer_setting(player, msg); + + __mmplayer_handle_buffering_message ( player ); + + msg_param.connection.buffering = player->streamer->buffering_percent; + MMPLAYER_POST_MSG ( player, MM_MESSAGE_BUFFERING, &msg_param ); + if (MMPLAYER_IS_RTSP_STREAMING(player) && (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) + { + if (player->doing_seek) + { + if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) + { + player->doing_seek = FALSE; + MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL ); + } + else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) + { + async_done = TRUE; + } + } + } + } + break; + + case GST_MESSAGE_STATE_CHANGED: + { + MMPlayerGstElement *mainbin; + const GValue *voldstate, *vnewstate, *vpending; + GstState oldstate, newstate, pending; + + if ( ! ( player->pipeline && player->pipeline->mainbin ) ) + { + debug_error("player pipeline handle is null"); + break; + } + + mainbin = player->pipeline->mainbin; + + /* we only handle messages from pipeline */ + if( msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst ) + break; + + /* get state info from msg */ + voldstate = gst_structure_get_value (gst_message_get_structure(msg), "old-state"); + vnewstate = gst_structure_get_value (gst_message_get_structure(msg), "new-state"); + vpending = gst_structure_get_value (gst_message_get_structure(msg), "pending-state"); + + oldstate = (GstState)voldstate->data[0].v_int; + newstate = (GstState)vnewstate->data[0].v_int; + pending = (GstState)vpending->data[0].v_int; + + debug_log("state changed [%s] : %s ---> %s final : %s\n", + GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), + gst_element_state_get_name( (GstState)oldstate ), + gst_element_state_get_name( (GstState)newstate ), + gst_element_state_get_name( (GstState)pending ) ); + + if (oldstate == newstate) + { + debug_log("pipeline reports state transition to old state"); + break; + } + + switch(newstate) + { + case GST_STATE_VOID_PENDING: + break; + + case GST_STATE_NULL: + break; + + case GST_STATE_READY: + break; + + case GST_STATE_PAUSED: + { + gboolean prepare_async = FALSE; + gboolean is_drm = FALSE; + + if ( ! player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex) + __mmplayer_configure_audio_callback(player); + + if ( ! player->sent_bos && oldstate == GST_STATE_READY) // managed prepare async case + { + mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async); + debug_log("checking prepare mode for async transition - %d", prepare_async); + } + + if ( MMPLAYER_IS_STREAMING(player) || prepare_async ) + { + MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PAUSED ); + + if (MMPLAYER_IS_STREAMING(player) && (player->streamer)) + { + __mm_player_streaming_set_content_bitrate(player->streamer, + player->total_maximum_bitrate, player->total_bitrate); + } + } + + /* NOTE : should consider streaming case */ + /* check if drm file */ + if ((player->pipeline->mainbin[MMPLAYER_M_SRC].gst) && + (g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm"))) + { + g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm", &is_drm, NULL); + + if (is_drm) + { + player->is_drm_file = TRUE; + } + } + } + break; + + case GST_STATE_PLAYING: + { +/* for audio tunning */ +#ifndef IS_SDK + if (player->can_support_codec == 0x03) { + gint volume_type; + mm_attrs_get_int_by_name(player->attrs, "sound_volume_type", &volume_type); + volume_type |= MM_SOUND_VOLUME_GAIN_VIDEO; + g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "volumetype", volume_type, NULL); + } +#endif + if ( MMPLAYER_IS_STREAMING(player) ) // managed prepare async case when buffering is completed + { + // pending state should be reset oyherwise, it's still playing even though it's resumed after bufferging. + if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) || + (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING)) + { + MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PLAYING); + } + } + + if (player->gapless.stream_changed) + { + _mmplayer_update_content_attrs(player, ATTR_ALL); + } + + if (player->doing_seek && async_done) + { + player->doing_seek = FALSE; + async_done = FALSE; + MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL ); + } + } + break; + + default: + break; + } + } + break; + + case GST_MESSAGE_CLOCK_LOST: + { + GstClock *clock = NULL; + gst_message_parse_clock_lost (msg, &clock); + debug_log("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL")); + g_print ("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL")); + + if (((player->ini.provide_clock_for_music) && (!player->videodec_linked)) || + ((player->ini.provide_clock_for_movie) && (player->videodec_linked))) + { + debug_log ("Provide clock is TRUE, do pause->resume\n"); + __gst_pause(player, FALSE); + __gst_resume(player, FALSE); + } + } + break; + + case GST_MESSAGE_NEW_CLOCK: + { + GstClock *clock = NULL; + gst_message_parse_new_clock (msg, &clock); + debug_log("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL")); + } + break; + + case GST_MESSAGE_ELEMENT: + { + const gchar *structure_name; + gint count = 0; + MMHandleType attrs = 0; + + attrs = MMPLAYER_GET_ATTRS(player); + if ( !attrs ) + { + debug_error("cannot get content attribute"); + ret = FALSE; + break; + } + + if(gst_message_get_structure(msg) == NULL) + break; + + structure_name = gst_structure_get_name(gst_message_get_structure(msg)); + if(!strcmp(structure_name, "Language_list")) + { + const GValue *lang_list = NULL; + lang_list = gst_structure_get_value (gst_message_get_structure(msg), "lang_list"); + if(lang_list != NULL) + { + count = g_list_length((GList *)g_value_get_pointer (lang_list)); + if (count > 1) + debug_log("Total audio tracks (from parser) = %d \n",count); + } + } + + if (!strcmp (structure_name, "Ext_Sub_Language_List")) + { + const GValue *lang_list = NULL; + MMPlayerLangStruct *temp = NULL; + + lang_list = gst_structure_get_value (gst_message_get_structure(msg), "lang_list"); + if (lang_list != NULL) + { + count = g_list_length ((GList *)g_value_get_pointer (lang_list)); + if (count) + { + player->subtitle_language_list = (GList *)g_value_get_pointer (lang_list); + mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count); + if (mmf_attrs_commit (attrs)) + debug_error("failed to commit.\n"); + debug_log("Total subtitle tracks = %d \n", count); + } + while (count) + { + temp = g_list_nth_data (player->subtitle_language_list, count - 1); + debug_log ("value of lang_key is %s and lang_code is %s", + temp->language_key, temp->language_code); + count--; + } + } + } + + /* custom message */ + if (!strcmp (structure_name, "audio_codec_not_supported")) { + MMMessageParamType msg_param = {0,}; + msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND; + MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param); + } + } + break; + + case GST_MESSAGE_DURATION_CHANGED: + { + debug_log("GST_MESSAGE_DURATION_CHANGED\n"); + ret = __mmplayer_gst_handle_duration(player, msg); + if (!ret) + { + debug_warning("failed to update duration"); + } + } + + break; + + case GST_MESSAGE_ASYNC_START: + { + debug_log("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg))); + } + break; + + case GST_MESSAGE_ASYNC_DONE: + { + debug_log("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg))); + + /* we only handle messages from pipeline */ + if( msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst ) + break; + + if (player->doing_seek) + { + if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) + { + player->doing_seek = FALSE; + MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL ); + } + else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) + { + if ((MMPLAYER_IS_HTTP_STREAMING(player)) && + (player->streamer) && + (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) && + (player->streamer->is_buffering == FALSE)) + { + GstQuery *query = NULL; + gboolean busy = FALSE; + gint percent = 0; + + if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) + { + query = gst_query_new_buffering ( GST_FORMAT_PERCENT ); + if ( gst_element_query (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query ) ) + { + gst_query_parse_buffering_percent ( query, &busy, &percent); + } + gst_query_unref (query); + + debug_log("buffered percent(%s): %d\n", + GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent); + } + + if (percent >= 100) + { + player->streamer->is_buffering = FALSE; + __mmplayer_handle_buffering_message(player); + } + } + + async_done = TRUE; + } + } + } + break; + + #if 0 /* delete unnecessary logs */ + case GST_MESSAGE_REQUEST_STATE: debug_log("GST_MESSAGE_REQUEST_STATE\n"); break; + case GST_MESSAGE_STEP_START: debug_log("GST_MESSAGE_STEP_START\n"); break; + case GST_MESSAGE_QOS: debug_log("GST_MESSAGE_QOS\n"); break; + case GST_MESSAGE_PROGRESS: debug_log("GST_MESSAGE_PROGRESS\n"); break; + case GST_MESSAGE_ANY: debug_log("GST_MESSAGE_ANY\n"); break; + case GST_MESSAGE_INFO: debug_log("GST_MESSAGE_STATE_DIRTY\n"); break; + case GST_MESSAGE_STATE_DIRTY: debug_log("GST_MESSAGE_STATE_DIRTY\n"); break; + case GST_MESSAGE_STEP_DONE: debug_log("GST_MESSAGE_STEP_DONE\n"); break; + case GST_MESSAGE_CLOCK_PROVIDE: debug_log("GST_MESSAGE_CLOCK_PROVIDE\n"); break; + case GST_MESSAGE_STRUCTURE_CHANGE: debug_log("GST_MESSAGE_STRUCTURE_CHANGE\n"); break; + case GST_MESSAGE_STREAM_STATUS: debug_log("GST_MESSAGE_STREAM_STATUS\n"); break; + case GST_MESSAGE_APPLICATION: debug_log("GST_MESSAGE_APPLICATION\n"); break; + case GST_MESSAGE_SEGMENT_START: debug_log("GST_MESSAGE_SEGMENT_START\n"); break; + case GST_MESSAGE_SEGMENT_DONE: debug_log("GST_MESSAGE_SEGMENT_DONE\n"); break; + case GST_MESSAGE_LATENCY: debug_log("GST_MESSAGE_LATENCY\n"); break; + #endif + + default: + break; + } + + /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since + * gst_element_post_message api takes ownership of the message. + */ + //gst_message_unref( msg ); + + return ret; +} + +static gboolean +__mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg) +{ + gint64 bytes = 0; + + MMPLAYER_FENTER(); + + return_val_if_fail(player, FALSE); + return_val_if_fail(msg, FALSE); + + if ((MMPLAYER_IS_HTTP_STREAMING(player)) && + (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) + { + debug_log("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src))); + + if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) + { + debug_log("data total size of http content: %lld", bytes); + player->http_content_size = bytes; + } + } + else + { + /* handling audio clip which has vbr. means duration is keep changing */ + _mmplayer_update_content_attrs (player, ATTR_DURATION ); + } + + MMPLAYER_FLEAVE(); + + return TRUE; +} + + +static gboolean +__mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg) // @ +{ + +/* macro for better code readability */ +#define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \ +if (gst_tag_list_get_string(tag_list, gsttag, &string)) \ +{\ + if (string != NULL)\ + {\ + secure_debug_log ( "update tag string : %s\n", string); \ + mm_attrs_set_string_by_name(attribute, playertag, string); \ + g_free(string);\ + string = NULL;\ + }\ +} + +#define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \ +GstSample *sample = NULL;\ +if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample))\ +{\ + GstMapInfo info = GST_MAP_INFO_INIT;\ + buffer = gst_sample_get_buffer(sample);\ + if (!gst_buffer_map(buffer, &info, GST_MAP_READ)){\ + debug_log("failed to get image data from tag");\ + return FALSE;\ + }\ + secure_debug_log ( "update album cover data : %p, size : %d\n", info.data, info.size);\ + MMPLAYER_FREEIF(player->album_art); \ + player->album_art = (gchar *)g_malloc(info.size); \ + if (player->album_art) \ + { \ + memcpy(player->album_art, info.data, info.size); \ + mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size); \ + if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) \ + { \ + msg_param.data = (void *)player->album_art; \ + msg_param.size = info.size; \ + MMPLAYER_POST_MSG (player, MM_MESSAGE_IMAGE_BUFFER, &msg_param); \ + secure_debug_log ( "post message image buffer data : %p, size : %d\n", info.data, info.size); \ + } \ + } \ + gst_buffer_unmap(buffer, &info); \ +} + +#define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \ +if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint))\ +{\ + if(v_uint)\ + {\ + if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) \ + {\ + if (player->updated_bitrate_count == 0) \ + mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \ + if (player->updated_bitrate_countbitrate[player->updated_bitrate_count] = v_uint;\ + player->total_bitrate += player->bitrate[player->updated_maximum_bitrate_count]; \ + player->updated_bitrate_count++; \ + mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate);\ + secure_debug_log ( "update bitrate %d[bps] of stream #%d.\n", v_uint, player->updated_bitrate_count);\ + }\ + }\ + else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) \ + {\ + if (player->updated_maximum_bitrate_countmaximum_bitrate[player->updated_maximum_bitrate_count] = v_uint;\ + player->total_maximum_bitrate += player->maximum_bitrate[player->updated_maximum_bitrate_count]; \ + player->updated_maximum_bitrate_count++; \ + mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate); \ + secure_debug_log ( "update maximum bitrate %d[bps] of stream #%d\n", v_uint, player->updated_maximum_bitrate_count);\ + }\ + }\ + else\ + {\ + mm_attrs_set_int_by_name(attribute, playertag, v_uint); \ + }\ + v_uint = 0;\ + }\ +} + +#define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \ +if (gst_tag_list_get_date(tag_list, gsttag, &date))\ +{\ + if (date != NULL)\ + {\ + string = g_strdup_printf("%d", g_date_get_year(date));\ + mm_attrs_set_string_by_name(attribute, playertag, string);\ + secure_debug_log ( "metainfo year : %s\n", string);\ + MMPLAYER_FREEIF(string);\ + g_date_free(date);\ + }\ +} + +#define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \ +if(gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64))\ +{\ + if(v_uint64)\ + {\ + /* FIXIT : don't know how to store date */\ + g_assert(1);\ + v_uint64 = 0;\ + }\ +} + +#define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \ +if(gst_tag_list_get_double(tag_list, gsttag, &v_double))\ +{\ + if(v_double)\ + {\ + /* FIXIT : don't know how to store date */\ + g_assert(1);\ + v_double = 0;\ + }\ +} + + /* function start */ + GstTagList* tag_list = NULL; + + MMHandleType attrs = 0; + + char *string = NULL; + guint v_uint = 0; + GDate *date = NULL; + /* album cover */ + GstBuffer *buffer = NULL; + gint index = 0; + MMMessageParamType msg_param = {0, }; + + /* currently not used. but those are needed for above macro */ + //guint64 v_uint64 = 0; + //gdouble v_double = 0; + + return_val_if_fail( player && msg, FALSE ); + + attrs = MMPLAYER_GET_ATTRS(player); + + return_val_if_fail( attrs, FALSE ); + + /* get tag list from gst message */ + gst_message_parse_tag(msg, &tag_list); + + /* store tags to player attributes */ + MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title"); + /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */ + MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist"); + /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */ + MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album"); + /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */ + MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author"); + MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date"); + MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre"); + /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */ + MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num"); + /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */ + MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description"); + /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */ + MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright"); + /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */ + MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec"); + MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec"); + MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate"); + MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate"); + MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover"); + /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */ + /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */ + MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation"); + + if ( mmf_attrs_commit ( attrs ) ) + debug_error("failed to commit.\n"); + + gst_tag_list_free(tag_list); + + return TRUE; +} + +static void +__mmplayer_gst_rtp_no_more_pads (GstElement *element, gpointer data) // @ +{ + mm_player_t* player = (mm_player_t*) data; + + MMPLAYER_FENTER(); + + /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever + * we connect autoplugging element to the pad which is just added to rtspsrc, we increase + * num_dynamic_pad. and this is no-more-pad situation which means mo more pad will be added. + * So we can say this. if num_dynamic_pad is zero, it must be one of followings + + * [1] audio and video will be dumped with filesink. + * [2] autoplugging is done by just using pad caps. + * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal + * and the video will be dumped via filesink. + */ + if ( player->num_dynamic_pad == 0 ) + { + debug_log("it seems pad caps is directely used for autoplugging. removing fakesink now\n"); + + if ( ! __mmplayer_gst_remove_fakesink( player, + &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]) ) + { + /* NOTE : __mmplayer_pipeline_complete() can be called several time. because + * signaling mechanism ( pad-added, no-more-pad, new-decoded-pad ) from various + * source element are not same. To overcome this situation, this function will called + * several places and several times. Therefore, this is not an error case. + */ + return; + } + } + + /* create dot before error-return. for debugging */ + MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-no-more-pad" ); + + player->no_more_pad = TRUE; + + MMPLAYER_FLEAVE(); +} + +static gboolean +__mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink) // @ +{ + GstElement* parent = NULL; + + return_val_if_fail(player && player->pipeline, FALSE); + + /* if we have no fakesink. this meas we are using decodebin which doesn' + t need to add extra fakesink */ + return_val_if_fail(fakesink, TRUE); + + /* lock */ + g_mutex_lock(&player->fsink_lock ); + + if ( ! fakesink->gst ) + { + goto ERROR; + } + + /* get parent of fakesink */ + parent = (GstElement*)gst_object_get_parent( (GstObject*)fakesink->gst ); + if ( ! parent ) + { + debug_log("fakesink already removed\n"); + goto ERROR; + } + + gst_element_set_locked_state( fakesink->gst, TRUE ); + + /* setting the state to NULL never returns async + * so no need to wait for completion of state transiton + */ + if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (fakesink->gst, GST_STATE_NULL) ) + { + debug_error("fakesink state change failure!\n"); + + /* FIXIT : should I return here? or try to proceed to next? */ + /* return FALSE; */ + } + + /* remove fakesink from it's parent */ + if ( ! gst_bin_remove( GST_BIN( parent ), fakesink->gst ) ) + { + debug_error("failed to remove fakesink\n"); + + gst_object_unref( parent ); + + goto ERROR; + } + + gst_object_unref( parent ); + + debug_log("state-holder removed\n"); + + gst_element_set_locked_state( fakesink->gst, FALSE ); + + g_mutex_unlock( &player->fsink_lock ); + return TRUE; + +ERROR: + if ( fakesink->gst ) + { + gst_element_set_locked_state( fakesink->gst, FALSE ); + } + + g_mutex_unlock( &player->fsink_lock ); + return FALSE; +} + + +static void +__mmplayer_gst_rtp_dynamic_pad (GstElement *element, GstPad *pad, gpointer data) // @ +{ + GstPad *sinkpad = NULL; + GstCaps* caps = NULL; + GstElement* new_element = NULL; + GstStructure* str = NULL; + const gchar* name = NULL; + + mm_player_t* player = (mm_player_t*) data; + + MMPLAYER_FENTER(); + + return_if_fail( element && pad ); + return_if_fail( player && + player->pipeline && + player->pipeline->mainbin ); + + + /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation. + * num_dynamic_pad will decreased after creating a sinkbin. + */ + player->num_dynamic_pad++; + debug_log("stream count inc : %d\n", player->num_dynamic_pad); + + /* perform autoplugging if dump is disabled */ + if ( player->ini.rtsp_do_typefinding ) + { + /* create typefind */ + new_element = gst_element_factory_make( "typefind", NULL ); + if ( ! new_element ) + { + debug_error("failed to create typefind\n"); + goto ERROR; + } + + MMPLAYER_SIGNAL_CONNECT( player, + G_OBJECT(new_element), + MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, + "have-type", + G_CALLBACK(__mmplayer_typefind_have_type), + (gpointer)player); + + /* FIXIT : try to remove it */ + player->have_dynamic_pad = FALSE; + } + else /* NOTE : use pad's caps directely. if enabled. what I am assuming is there's no elemnt has dynamic pad */ + { + debug_log("using pad caps to autopluging instead of doing typefind\n"); + + caps = gst_pad_query_caps( pad, NULL ); + + MMPLAYER_CHECK_NULL( caps ); + + /* clear previous result*/ + player->have_dynamic_pad = FALSE; + + str = gst_caps_get_structure(caps, 0); + + if ( ! str ) + { + debug_error ("cannot get structure from caps.\n"); + goto ERROR; + } + + name = gst_structure_get_name (str); + if ( ! name ) + { + debug_error ("cannot get mimetype from structure.\n"); + goto ERROR; + } + + if (strstr(name, "video")) + { + gint stype = 0; + mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype); + + if (stype == MM_DISPLAY_SURFACE_NULL) + { + if (player->v_stream_caps) + { + gst_caps_unref(player->v_stream_caps); + player->v_stream_caps = NULL; + } + + new_element = gst_element_factory_make("fakesink", NULL); + player->num_dynamic_pad--; + goto NEW_ELEMENT; + } + } + + /* clear previous result*/ + player->have_dynamic_pad = FALSE; + + if ( !__mmplayer_try_to_plug_decodebin(player, pad, caps)) + { + debug_error("failed to autoplug for caps"); + goto ERROR; + } + + /* check if there's dynamic pad*/ + if( player->have_dynamic_pad ) + { + debug_error("using pad caps assums there's no dynamic pad !\n"); + debug_error("try with enalbing rtsp_do_typefinding\n"); + goto ERROR; + } + + gst_caps_unref( caps ); + caps = NULL; + } + + NEW_ELEMENT: + + /* excute new_element if created*/ + if ( new_element ) + { + debug_log("adding new element to pipeline\n"); + + /* set state to READY before add to bin */ + MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_READY ); + + /* add new element to the pipeline */ + if ( FALSE == gst_bin_add( GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element) ) + { + debug_error("failed to add autoplug element to bin\n"); + goto ERROR; + } + + /* get pad from element */ + sinkpad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "sink" ); + if ( !sinkpad ) + { + debug_error("failed to get sinkpad from autoplug element\n"); + goto ERROR; + } + + /* link it */ + if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) ) + { + debug_error("failed to link autoplug element\n"); + goto ERROR; + } + + gst_object_unref (sinkpad); + sinkpad = NULL; + + /* run. setting PLAYING here since streamming source is live source */ + MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_PLAYING ); + } + + MMPLAYER_FLEAVE(); + + return; + +STATE_CHANGE_FAILED: +ERROR: + /* FIXIT : take care if new_element has already added to pipeline */ + if ( new_element ) + gst_object_unref(GST_OBJECT(new_element)); + + if ( sinkpad ) + gst_object_unref(GST_OBJECT(sinkpad)); + + if ( caps ) + gst_object_unref(GST_OBJECT(caps)); + + /* FIXIT : how to inform this error to MSL ????? */ + /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and + * then post an error to application + */ +} + + + +/* FIXIT : check indent */ +#if 0 +static void +__mmplayer_gst_wfd_dynamic_pad (GstElement *element, GstPad *pad, gpointer data) // @ +{ + GstPad *sinkpad = NULL; + GstCaps* caps = NULL; + GstElement* new_element = NULL; + enum MainElementID element_id = MMPLAYER_M_NUM; + + mm_player_t* player = (mm_player_t*) data; + + MMPLAYER_FENTER(); + + return_if_fail( element && pad ); + return_if_fail( player && + player->pipeline && + player->pipeline->mainbin ); + + debug_log("stream count inc : %d\n", player->num_dynamic_pad); + + { + debug_log("using pad caps to autopluging instead of doing typefind\n"); + caps = gst_pad_query_caps( pad ); + MMPLAYER_CHECK_NULL( caps ); + /* clear previous result*/ + player->have_dynamic_pad = FALSE; + new_element = gst_element_factory_make("rtpmp2tdepay", "wfd_rtp_depay"); + if ( !new_element ) + { + debug_error ( "failed to create wfd rtp depay element\n" ); + goto ERROR; + } + MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_READY ); + /* add new element to the pipeline */ + if ( FALSE == gst_bin_add( GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element) ) + { + debug_log("failed to add autoplug element to bin\n"); + goto ERROR; + } + /* get pad from element */ + sinkpad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "sink" ); + if ( !sinkpad ) + { + debug_log("failed to get sinkpad from autoplug element\n"); + goto ERROR; + } + /* link it */ + if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) ) + { + debug_log("failed to link autoplug element\n"); + goto ERROR; + } + gst_object_unref (sinkpad); + sinkpad = NULL; + pad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "src" ); + caps = gst_pad_query_caps( pad ); + MMPLAYER_CHECK_NULL( caps ); + MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_PLAYING ); + /* create typefind */ + new_element = gst_element_factory_make( "typefind", NULL ); + if ( ! new_element ) + { + debug_log("failed to create typefind\n"); + goto ERROR; + } + + MMPLAYER_SIGNAL_CONNECT( player, + G_OBJECT(new_element), + MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, + "have-type", + G_CALLBACK(__mmplayer_typefind_have_type), + (gpointer)player); + + player->have_dynamic_pad = FALSE; + } + + /* excute new_element if created*/ + if ( new_element ) + { + debug_log("adding new element to pipeline\n"); + + /* set state to READY before add to bin */ + MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_READY ); + + /* add new element to the pipeline */ + if ( FALSE == gst_bin_add( GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element) ) + { + debug_log("failed to add autoplug element to bin\n"); + goto ERROR; + } + + /* get pad from element */ + sinkpad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "sink" ); + if ( !sinkpad ) + { + debug_log("failed to get sinkpad from autoplug element\n"); + goto ERROR; + } + + /* link it */ + if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) ) + { + debug_log("failed to link autoplug element\n"); + goto ERROR; + } + + gst_object_unref (sinkpad); + sinkpad = NULL; + + /* run. setting PLAYING here since streamming source is live source */ + MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_PLAYING ); + } + + /* store handle to futher manipulation */ + player->pipeline->mainbin[element_id].id = element_id; + player->pipeline->mainbin[element_id].gst = new_element; + + MMPLAYER_FLEAVE(); + + return; + +STATE_CHANGE_FAILED: +ERROR: + /* FIXIT : take care if new_element has already added to pipeline */ + if ( new_element ) + gst_object_unref(GST_OBJECT(new_element)); + + if ( sinkpad ) + gst_object_unref(GST_OBJECT(sinkpad)); + + if ( caps ) + gst_object_unref(GST_OBJECT(caps)); + + /* FIXIT : how to inform this error to MSL ????? */ + /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and + * then post an error to application + */ +} +#endif + +static GstPadProbeReturn +__mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data) +{ + debug_log ("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad)); + return GST_PAD_PROBE_OK; +} + +static GstPadProbeReturn +__mmplayer_audio_data_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data) +{ + mm_player_t* player = (mm_player_t*) u_data; + GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info); + + /* TO_CHECK: performance */ + return_val_if_fail (player && GST_IS_BUFFER(pad_buffer), GST_PAD_PROBE_OK); + + if (GST_BUFFER_PTS_IS_VALID(pad_buffer) && GST_BUFFER_DURATION_IS_VALID(pad_buffer)) + player->gapless.next_pts = GST_BUFFER_PTS(pad_buffer) + GST_BUFFER_DURATION(pad_buffer); + + return GST_PAD_PROBE_OK; +} + +static GstPadProbeReturn +__mmplayer_gst_selector_event_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data) +{ + GstPadProbeReturn ret = GST_PAD_PROBE_OK; + GstEvent *event = GST_PAD_PROBE_INFO_DATA (info); + mm_player_t* player = (mm_player_t*)data; + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_STREAM_START: + break; + case GST_EVENT_SEGMENT: { + GstSegment segment; + GstEvent *tmpev; + + if (!player->gapless.running) + break; + + if (player->gapless.stream_changed) { + player->gapless.start_time += player->gapless.next_pts; + player->gapless.stream_changed = FALSE; + } + + debug_log ("event: %" GST_PTR_FORMAT, event); + gst_event_copy_segment (event, &segment); + + if (segment.format == GST_FORMAT_TIME) + { + segment.base = player->gapless.start_time; + debug_log ("base of segment: %" GST_TIME_FORMAT, GST_TIME_ARGS (segment.base)); + + tmpev = gst_event_new_segment (&segment); + gst_event_set_seqnum (tmpev, gst_event_get_seqnum (event)); + gst_event_unref (event); + GST_PAD_PROBE_INFO_DATA(info) = tmpev; + } + break; + } + default: + break; + } + return ret; +} + +static void +__mmplayer_gst_decode_pad_added (GstElement *elem, GstPad *pad, gpointer data) +{ + mm_player_t* player = NULL; + GstElement* pipeline = NULL; + GstElement* selector = NULL; + GstElement* fakesink = NULL; + GstCaps* caps = NULL; + GstStructure* str = NULL; + const gchar* name = NULL; + GstPad* sinkpad = NULL; + GstPad* srcpad = NULL; + gboolean first_track = FALSE; + + enum MainElementID elemId = MMPLAYER_M_NUM; + MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO; + + /* check handles */ + player = (mm_player_t*)data; + + return_if_fail (elem && pad); + return_if_fail (player && player->pipeline && player->pipeline->mainbin); + + //debug_log ("pad-added signal handling\n"); + + pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst; + + /* get mimetype from caps */ + caps = gst_pad_query_caps (pad, NULL); + if ( !caps ) + { + debug_error ("cannot get caps from pad.\n"); + goto ERROR; + } + + str = gst_caps_get_structure (caps, 0); + if ( ! str ) + { + debug_error ("cannot get structure from caps.\n"); + goto ERROR; + } + + name = gst_structure_get_name (str); + if ( ! name ) + { + debug_error ("cannot get mimetype from structure.\n"); + goto ERROR; + } + + MMPLAYER_LOG_GST_CAPS_TYPE(caps); + //debug_log ("detected mimetype : %s\n", name); + + if (strstr(name, "video")) + { + gint stype = 0; + mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype); + + /* don't make video because of not required, and not support multiple track */ + if (stype == MM_DISPLAY_SURFACE_NULL) + { + debug_log ("no video sink by null surface or multiple track"); + gchar *caps_str = gst_caps_to_string(caps); + if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12")) + { + player->set_mode.video_zc = TRUE; + } + MMPLAYER_FREEIF( caps_str ); + + if (player->v_stream_caps) + { + gst_caps_unref(player->v_stream_caps); + player->v_stream_caps = NULL; + } + + debug_log ("create fakesink instead of videobin"); + + /* fake sink */ + fakesink = gst_element_factory_make ("fakesink", NULL); + if (fakesink == NULL) + { + debug_error ("ERROR : fakesink create error\n"); + goto ERROR; + } + + player->video_fakesink = fakesink; + + gst_bin_add (GST_BIN(pipeline), fakesink); + + // link + sinkpad = gst_element_get_static_pad (fakesink, "sink"); + + if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) + { + debug_warning ("failed to link fakesink\n"); + gst_object_unref (GST_OBJECT(fakesink)); + goto ERROR; + } + + if (player->set_mode.media_packet_video_stream) + player->video_cb_probe_id = gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_BUFFER, __mmplayer_video_stream_probe, player, NULL); + + g_object_set (G_OBJECT (fakesink), "async", TRUE, NULL); + g_object_set (G_OBJECT (fakesink), "sync", TRUE, NULL); + gst_element_set_state (fakesink, GST_STATE_PAUSED); + + goto DONE; + } + __mmplayer_gst_decode_callback (elem, pad, player); + } + else + { + if (strstr(name, "audio")) + { + gint samplerate = 0; + gint channels = 0; + + if (MMPLAYER_IS_ES_BUFF_SRC(player)) + { + __mmplayer_gst_decode_callback (elem, pad, player); + return; + } + + debug_log ("audio selector \n"); + elemId = MMPLAYER_M_A_INPUT_SELECTOR; + stream_type = MM_PLAYER_TRACK_TYPE_AUDIO; + + gst_structure_get_int (str, "rate", &samplerate); + gst_structure_get_int (str, "channels", &channels); + + if ((channels > 0 && samplerate == 0)) {//exclude audio decoding + /* fake sink */ + fakesink = gst_element_factory_make ("fakesink", NULL); + if (fakesink == NULL) + { + debug_error ("ERROR : fakesink create error\n"); + goto ERROR; + } + + gst_bin_add (GST_BIN(pipeline), fakesink); + + /* link */ + sinkpad = gst_element_get_static_pad (fakesink, "sink"); + + if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) + { + debug_warning ("failed to link fakesink\n"); + gst_object_unref (GST_OBJECT(fakesink)); + goto ERROR; + } + + g_object_set (G_OBJECT (fakesink), "async", TRUE, NULL); + g_object_set (G_OBJECT (fakesink), "sync", TRUE, NULL); + gst_element_set_state (fakesink, GST_STATE_PAUSED); + + goto DONE; + } + } + else if (strstr(name, "text")) + { + debug_log ("text selector \n"); + elemId = MMPLAYER_M_T_INPUT_SELECTOR; + stream_type = MM_PLAYER_TRACK_TYPE_TEXT; + } + else + { + debug_error ("wrong elem id \n"); + goto ERROR; + } + } + + if(strstr(name, "video")) + return; + + selector = player->pipeline->mainbin[elemId].gst; + + if (selector == NULL) + { + selector = gst_element_factory_make ("input-selector", NULL); + debug_log ("Creating input-selector\n"); + if (selector == NULL) + { + debug_error ("ERROR : input-selector create error\n"); + goto ERROR; + } + g_object_set (selector, "sync-streams", TRUE, NULL); + + player->pipeline->mainbin[elemId].id = elemId; + player->pipeline->mainbin[elemId].gst = selector; + + first_track = TRUE; + // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default + + srcpad = gst_element_get_static_pad (selector, "src"); + + debug_log ("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad)); + player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, + __mmplayer_gst_selector_blocked, NULL, NULL); + player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, + __mmplayer_gst_selector_event_probe, player, NULL); + + gst_element_set_state (selector, GST_STATE_PAUSED); + gst_bin_add (GST_BIN(pipeline), selector); + } + else + { + debug_log ("input-selector is already created.\n"); + selector = player->pipeline->mainbin[elemId].gst; + } + + // link + debug_log ("Calling request pad with selector %p \n", selector); + sinkpad = gst_element_get_request_pad (selector, "sink_%u"); + + debug_log ("got pad %s:%s from selector", GST_DEBUG_PAD_NAME (sinkpad)); + + if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) + { + debug_warning ("failed to link selector\n"); + gst_object_unref (GST_OBJECT(selector)); + goto ERROR; + } + + if (first_track) + { + debug_log ("this is first track --> active track \n"); + g_object_set (selector, "active-pad", sinkpad, NULL); + } + + _mmplayer_track_update_info(player, stream_type, sinkpad); + + +DONE: +ERROR: + + if (caps) + { + gst_caps_unref (caps); + } + + if (sinkpad) + { + gst_object_unref (GST_OBJECT(sinkpad)); + sinkpad = NULL; + } + + if (srcpad) + { + gst_object_unref (GST_OBJECT(srcpad)); + srcpad = NULL; + } + + return; +} + +static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector) +{ + GstPad* srcpad = NULL; + MMHandleType attrs = 0; + gint active_index = 0; + + // [link] input-selector :: textbin + srcpad = gst_element_get_static_pad (text_selector, "src"); + if (!srcpad) + { + debug_error("failed to get srcpad from selector\n"); + return; + } + + debug_log ("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad)); + + active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index; + if ((active_index != DEFAULT_TRACK) && + (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) + { + debug_warning("failed to change text track\n"); + player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK; + } + + player->no_more_pad = TRUE; + __mmplayer_gst_decode_callback (text_selector, srcpad, player); + + debug_log ("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad)); + if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) + { + gst_pad_remove_probe (srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id); + player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0; + } + + debug_log("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num); + + if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0) + player->has_closed_caption = TRUE; + + attrs = MMPLAYER_GET_ATTRS(player); + if ( attrs ) + { + mm_attrs_set_int_by_name(attrs, "content_text_track_num",(gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num); + if (mmf_attrs_commit (attrs)) + debug_error("failed to commit.\n"); + } + else + { + debug_error("cannot get content attribute"); + } + + if (srcpad) + { + gst_object_unref ( GST_OBJECT(srcpad) ); + srcpad = NULL; + } +} + +int _mmplayer_gst_set_audio_channel(MMHandleType hplayer, MMPlayerAudioChannel ch_idx) +{ + int result = MM_ERROR_NONE; + + mm_player_t* player = (mm_player_t*)hplayer; + MMPlayerGstElement* mainbin = NULL; + gchar* change_pad_name = NULL; + GstPad* sinkpad = NULL; + GstCaps* caps = NULL; + + MMPLAYER_FENTER(); + + return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + debug_log ("Change Audio mode to %d\n", ch_idx); + player->use_deinterleave = TRUE; + + if ((!player->pipeline) || (!player->pipeline->mainbin)) + { + debug_log ("pre setting : %d\n", ch_idx); + + player->audio_mode.active_pad_index = ch_idx; + return result; + } + + mainbin = player->pipeline->mainbin; + + if (mainbin[MMPLAYER_M_A_SELECTOR].gst == NULL) + { + if (player->max_audio_channels < 2) + { + debug_log ("mono channel track only\n"); + return result; + } + + debug_warning ("selector doesn't exist\n"); + return result; /* keep playing */ + } + + debug_log ("total_ch_num : %d\n", player->audio_mode.total_track_num); + + if (player->audio_mode.total_track_num < 2) + { + debug_warning ("there is no another audio path\n"); + return result; /* keep playing */ + } + + if ((ch_idx < 0) || (ch_idx >= player->audio_mode.total_track_num)) + { + debug_warning ("Not a proper ch_idx : %d \n", ch_idx); + return result; /* keep playing */ + } + + /*To get the new pad from the selector*/ + change_pad_name = g_strdup_printf ("sink%d", ch_idx); + if (change_pad_name == NULL) + { + debug_warning ("Pad does not exists\n"); + goto ERROR; /* keep playing */ + } + + debug_log ("new active pad name: %s\n", change_pad_name); + + sinkpad = gst_element_get_static_pad (mainbin[MMPLAYER_M_A_SELECTOR].gst, change_pad_name); + if (sinkpad == NULL) + { + //result = MM_ERROR_PLAYER_INTERNAL; + goto ERROR; /* keep playing */ + } + + debug_log ("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad)); + g_object_set (mainbin[MMPLAYER_M_A_SELECTOR].gst, "active-pad", sinkpad, NULL); + + caps = gst_pad_get_current_caps(sinkpad); + MMPLAYER_LOG_GST_CAPS_TYPE(caps); + + __mmplayer_set_audio_attrs (player, caps); + player->audio_mode.active_pad_index = ch_idx; + +ERROR: + + if (sinkpad) + gst_object_unref (sinkpad); + + MMPLAYER_FREEIF(change_pad_name); + + MMPLAYER_FLEAVE(); + return result; +} + + + +static void +__mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data) +{ + mm_player_t* player = (mm_player_t*)data; + GstElement* selector = NULL; + GstElement* queue = NULL; + + GstPad* srcpad = NULL; + GstPad* sinkpad = NULL; + gchar* caps_str= NULL; + + MMPLAYER_FENTER(); + return_if_fail (player && player->pipeline && player->pipeline->mainbin); + + caps_str = gst_caps_to_string(gst_pad_get_current_caps(pad)); + debug_log ("deinterleave new caps : %s\n", caps_str); + MMPLAYER_FREEIF(caps_str); + + if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) + { + debug_error ("ERROR : queue create error\n"); + goto ERROR; + } + + g_object_set(G_OBJECT(queue), + "max-size-buffers", 10, + "max-size-bytes", 0, + "max-size-time", (guint64)0, + NULL); + + selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst; + + if (!selector) + { + debug_error("there is no audio channel selector.\n"); + goto ERROR; + } + + srcpad = gst_element_get_static_pad (queue, "src"); + sinkpad = gst_element_get_request_pad (selector, "sink_%u"); + + debug_log ("link (%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad)); + + if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) + { + debug_warning ("failed to link deinterleave - selector\n"); + goto ERROR; + } + + gst_element_set_state (queue, GST_STATE_PAUSED); + player->audio_mode.total_track_num++; + +ERROR: + + if (srcpad) + { + gst_object_unref ( GST_OBJECT(srcpad) ); + srcpad = NULL; + } + + if (sinkpad) + { + gst_object_unref ( GST_OBJECT(sinkpad) ); + sinkpad = NULL; + } + + MMPLAYER_FLEAVE(); + return; +} + +static void +__mmplayer_gst_deinterleave_no_more_pads (GstElement *elem, gpointer data) +{ + mm_player_t* player = NULL; + GstElement* selector = NULL; + GstPad* sinkpad = NULL; + gint active_index = 0; + gchar* change_pad_name = NULL; + GstCaps* caps = NULL; // no need to unref + + MMPLAYER_FENTER(); + player = (mm_player_t*) data; + + selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst; + + if (!selector) + { + debug_error("there is no audio channel selector.\n"); + goto ERROR; + } + + active_index = player->audio_mode.active_pad_index; + + if (active_index != DEFAULT_AUDIO_CH) + { + gint audio_ch = DEFAULT_AUDIO_CH; + + /*To get the new pad from the selector*/ + change_pad_name = g_strdup_printf ("sink%d", active_index); + if (change_pad_name != NULL) + { + sinkpad = gst_element_get_static_pad (selector, change_pad_name); + if (sinkpad != NULL) + { + debug_log ("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad)); + g_object_set (selector, "active-pad", sinkpad, NULL); + + audio_ch = active_index; + + caps = gst_pad_get_current_caps(sinkpad); + MMPLAYER_LOG_GST_CAPS_TYPE(caps); + + __mmplayer_set_audio_attrs (player, caps); + } + } + + player->audio_mode.active_pad_index = audio_ch; + debug_log("audio LR info (0:stereo) = %d\n", player->audio_mode.active_pad_index); + } + +ERROR: + + if (sinkpad) + gst_object_unref (sinkpad); + + MMPLAYER_FLEAVE(); + return; +} + +static void +__mmplayer_gst_build_deinterleave_path (GstElement *elem, GstPad *pad, gpointer data) +{ + mm_player_t* player = NULL; + MMPlayerGstElement *mainbin = NULL; + + GstElement* tee = NULL; + GstElement* stereo_queue = NULL; + GstElement* mono_queue = NULL; + GstElement* conv = NULL; + GstElement* filter = NULL; + GstElement* deinterleave = NULL; + GstElement* selector = NULL; + + GstPad* srcpad = NULL; + GstPad* selector_srcpad = NULL; + GstPad* sinkpad = NULL; + GstCaps* caps = NULL; + gulong block_id = 0; + + MMPLAYER_FENTER(); + + /* check handles */ + player = (mm_player_t*) data; + + return_if_fail( elem && pad ); + return_if_fail( player && player->pipeline && player->pipeline->mainbin ); + + mainbin = player->pipeline->mainbin; + + /* tee */ + if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) + { + debug_error ("ERROR : tee create error\n"); + goto ERROR; + } + + mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE; + mainbin[MMPLAYER_M_A_TEE].gst = tee; + + gst_element_set_state (tee, GST_STATE_PAUSED); + + /* queue */ + srcpad = gst_element_get_request_pad (tee, "src_%u"); + if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) + { + debug_error ("ERROR : stereo queue create error\n"); + goto ERROR; + } + + g_object_set(G_OBJECT(stereo_queue), + "max-size-buffers", 10, + "max-size-bytes", 0, + "max-size-time", (guint64)0, + NULL); + + player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1; + player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue; + + if (srcpad) + { + gst_object_unref (GST_OBJECT(srcpad)); + srcpad = NULL; + } + + srcpad = gst_element_get_request_pad (tee, "src_%u"); + + if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) + { + debug_error ("ERROR : mono queue create error\n"); + goto ERROR; + } + + g_object_set(G_OBJECT(mono_queue), + "max-size-buffers", 10, + "max-size-bytes", 0, + "max-size-time", (guint64)0, + NULL); + + player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2; + player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue; + + gst_element_set_state (stereo_queue, GST_STATE_PAUSED); + gst_element_set_state (mono_queue, GST_STATE_PAUSED); + + /* audioconvert */ + srcpad = gst_element_get_static_pad (mono_queue, "src"); + if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) + { + debug_error ("ERROR : audioconvert create error\n"); + goto ERROR; + } + + player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV; + player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv; + + /* caps filter */ + if (srcpad) + { + gst_object_unref (GST_OBJECT(srcpad)); + srcpad = NULL; + } + srcpad = gst_element_get_static_pad (conv, "src"); + + if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) + { + debug_error ("ERROR : capsfilter create error\n"); + goto ERROR; + } + + player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER; + player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter; + + caps = gst_caps_from_string( "audio/x-raw-int, " + "width = (int) 16, " + "depth = (int) 16, " + "channels = (int) 2"); + + g_object_set (GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL ); + gst_caps_unref( caps ); + + gst_element_set_state (conv, GST_STATE_PAUSED); + gst_element_set_state (filter, GST_STATE_PAUSED); + + /* deinterleave */ + if (srcpad) + { + gst_object_unref (GST_OBJECT(srcpad)); + srcpad = NULL; + } + srcpad = gst_element_get_static_pad (filter, "src"); + + if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) + { + debug_error ("ERROR : deinterleave create error\n"); + goto ERROR; + } + + g_object_set (deinterleave, "keep-positions", TRUE, NULL); + + MMPLAYER_SIGNAL_CONNECT (player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", + G_CALLBACK (__mmplayer_gst_deinterleave_pad_added), player); + + MMPLAYER_SIGNAL_CONNECT (player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", + G_CALLBACK (__mmplayer_gst_deinterleave_no_more_pads), player); + + player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE; + player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave; + + /* selector */ + selector = gst_element_factory_make ("input-selector", "audio-channel-selector"); + if (selector == NULL) + { + debug_error ("ERROR : audio-selector create error\n"); + goto ERROR; + } + + g_object_set (selector, "sync-streams", TRUE, NULL); + gst_bin_add (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector); + + player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR; + player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector; + + selector_srcpad = gst_element_get_static_pad (selector, "src"); + + debug_log ("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad)); + block_id = + gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, + __mmplayer_gst_selector_blocked, NULL, NULL); + + if (srcpad) + { + gst_object_unref (GST_OBJECT(srcpad)); + srcpad = NULL; + } + + srcpad = gst_element_get_static_pad(stereo_queue, "src"); + sinkpad = gst_element_get_request_pad (selector, "sink_%u"); + + if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) + { + debug_warning ("failed to link queue_stereo - selector\n"); + goto ERROR; + } + + player->audio_mode.total_track_num++; + + g_object_set (selector, "active-pad", sinkpad, NULL); + gst_element_set_state (deinterleave, GST_STATE_PAUSED); + gst_element_set_state (selector, GST_STATE_PAUSED); + + __mmplayer_gst_decode_callback (selector, selector_srcpad, player); + +ERROR: + + debug_log ("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad)); + if (block_id != 0) + { + gst_pad_remove_probe (selector_srcpad, block_id); + block_id = 0; + } + + if (sinkpad) + { + gst_object_unref (GST_OBJECT(sinkpad)); + sinkpad = NULL; + } + + if (srcpad) + { + gst_object_unref (GST_OBJECT(srcpad)); + srcpad = NULL; + } + + if (selector_srcpad) + { + gst_object_unref (GST_OBJECT(selector_srcpad)); + selector_srcpad = NULL; + } + + MMPLAYER_FLEAVE(); + return; +} + +static void +__mmplayer_gst_decode_no_more_pads (GstElement *elem, gpointer data) +{ + mm_player_t* player = NULL; + GstPad* srcpad = NULL; + GstElement* audio_selector = NULL; + GstElement* text_selector = NULL; + MMHandleType attrs = 0; + gint active_index = 0; + gint64 dur_bytes = 0L; + + player = (mm_player_t*) data; + + debug_log("no-more-pad signal handling\n"); + + if ((player->cmd == MMPLAYER_COMMAND_DESTROY) || + (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) + { + debug_warning("no need to go more"); + + if (player->gapless.reconfigure) + { + player->gapless.reconfigure = FALSE; + MMPLAYER_PLAYBACK_UNLOCK(player); + } + + return; + } + + if ((!MMPLAYER_IS_HTTP_PD(player)) && + (MMPLAYER_IS_HTTP_STREAMING(player)) && + (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) && + (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) + { + #define ESTIMATED_BUFFER_UNIT (1*1024*1024) + + if (NULL == player->streamer) + { + debug_warning("invalid state for buffering"); + goto ERROR; + } + + gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second; + guint buffer_bytes = init_buffering_time * ESTIMATED_BUFFER_UNIT; + + buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes); + debug_log("[Decodebin2] set use-buffering on Q2 (pre buffer time: %d sec, buffer size : %d)\n", (gint)init_buffering_time, buffer_bytes); + + init_buffering_time = (init_buffering_time != 0)?(init_buffering_time):(player->ini.http_buffering_time); + + if ( !gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes)) + debug_error("fail to get duration.\n"); + + // enable use-buffering on queue2 instead of multiqueue (ex)audio only streaming + // use file information was already set on Q2 when it was created. + __mm_player_streaming_set_queue2(player->streamer, + player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, + TRUE, // use_buffering + buffer_bytes, + init_buffering_time, + 1.0, // low percent + player->ini.http_buffering_limit, // high percent + FALSE, + NULL, + ((dur_bytes>0)?((guint64)dur_bytes):0)); + } + audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst; + text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst; + if (audio_selector) + { + active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index; + if ((active_index != DEFAULT_TRACK) && + (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) + { + debug_warning("failed to change audio track\n"); + player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK; + } + + // [link] input-selector :: audiobin + srcpad = gst_element_get_static_pad (audio_selector, "src"); + if (!srcpad) + { + debug_error("failed to get srcpad from selector\n"); + goto ERROR; + } + + debug_log ("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad)); + if (!text_selector) + player->no_more_pad = TRUE; + + if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) + { + debug_log ("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad)); + if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) + { + gst_pad_remove_probe (srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id); + player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0; + } + + __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player); + } + else + { + __mmplayer_gst_decode_callback (audio_selector, srcpad, player); + + debug_log ("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad)); + if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) + { + gst_pad_remove_probe (srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id); + player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0; + } + } + + debug_log("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num); + + attrs = MMPLAYER_GET_ATTRS(player); + if ( attrs ) + { + mm_attrs_set_int_by_name(attrs, "content_audio_track_num",(gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num); + if (mmf_attrs_commit (attrs)) + debug_error("failed to commit.\n"); + } + else + { + debug_error("cannot get content attribute"); + } + } + else + { + if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) + { + debug_log ("There is no audio track : remove audiobin"); + + __mmplayer_release_signal_connection( player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN ); + __mmplayer_del_sink ( player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst ); + + MMPLAYER_RELEASE_ELEMENT ( player, player->pipeline->audiobin, MMPLAYER_A_BIN ); + MMPLAYER_FREEIF ( player->pipeline->audiobin ) + } + + if (player->num_dynamic_pad == 0) + { + __mmplayer_pipeline_complete (NULL, player); + } + } + + + if (!MMPLAYER_IS_ES_BUFF_SRC(player)) + { + if (text_selector) + { + __mmplayer_handle_text_decode_path(player, text_selector); + } + } + + MMPLAYER_FLEAVE(); + +ERROR: + if (srcpad) + { + gst_object_unref ( GST_OBJECT(srcpad) ); + srcpad = NULL; + } + + if (player->gapless.reconfigure) + { + player->gapless.reconfigure = FALSE; + MMPLAYER_PLAYBACK_UNLOCK(player); + } +} + +static void +__mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data) // @ +{ + mm_player_t* player = NULL; + MMHandleType attrs = 0; + GstElement* pipeline = NULL; + GstCaps* caps = NULL; + gchar* caps_str = NULL; + GstStructure* str = NULL; + const gchar* name = NULL; + GstPad* sinkpad = NULL; + GstElement* sinkbin = NULL; + gboolean reusing = FALSE; + GstElement *text_selector = NULL; + + /* check handles */ + player = (mm_player_t*) data; + + return_if_fail( elem && pad ); + return_if_fail(player && player->pipeline && player->pipeline->mainbin); + + pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst; + + attrs = MMPLAYER_GET_ATTRS(player); + if ( !attrs ) + { + debug_error("cannot get content attribute\n"); + goto ERROR; + } + + /* get mimetype from caps */ + caps = gst_pad_query_caps( pad, NULL ); + if ( !caps ) + { + debug_error("cannot get caps from pad.\n"); + goto ERROR; + } + caps_str = gst_caps_to_string(caps); + + str = gst_caps_get_structure( caps, 0 ); + if ( ! str ) + { + debug_error("cannot get structure from caps.\n"); + goto ERROR; + } + + name = gst_structure_get_name(str); + if ( ! name ) + { + debug_error("cannot get mimetype from structure.\n"); + goto ERROR; + } + + //debug_log("detected mimetype : %s\n", name); + + if (strstr(name, "audio")) + { + if (player->pipeline->audiobin == NULL) + { + if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) + { + debug_error("failed to create audiobin. continuing without audio\n"); + goto ERROR; + } + + sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst; + debug_log("creating audiosink bin success\n"); + } + else + { + reusing = TRUE; + sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst; + debug_log("reusing audiobin\n"); + _mmplayer_update_content_attrs( player, ATTR_AUDIO); + } + + if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks + mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1); + + player->audiosink_linked = 1; + + sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "sink" ); + if ( !sinkpad ) + { + debug_error("failed to get pad from sinkbin\n"); + goto ERROR; + } + } + else if (strstr(name, "video")) + { + if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12")) + { + player->set_mode.video_zc = TRUE; + } + + if (player->pipeline->videobin == NULL) + { + /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */ + /* get video surface type */ + int surface_type = 0; + mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type); + + if (surface_type == MM_DISPLAY_SURFACE_NULL) + { + debug_log("not make videobin because it dose not want\n"); + goto ERROR; + } + + if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type) ) + { + debug_error("failed to create videobin. continuing without video\n"); + goto ERROR; + } + + sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst; + debug_log("creating videosink bin success\n"); + } + else + { + reusing = TRUE; + sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst; + debug_log("re-using videobin\n"); + _mmplayer_update_content_attrs( player, ATTR_VIDEO); + } + + /* FIXIT : track number shouldn't be hardcoded */ + mm_attrs_set_int_by_name(attrs, "content_video_track_num", 1); + player->videosink_linked = 1; + + /* NOTE : intermediate code before doing H/W subtitle compositon */ + if ( player->use_textoverlay && player->play_subtitle ) + { + debug_log("using textoverlay for external subtitle"); + /* check text bin has created well */ + if ( player->pipeline && player->pipeline->textbin ) + { + /* get sinkpad from textoverlay */ + sinkpad = gst_element_get_static_pad( + GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst), + "video_sink" ); + if ( ! sinkpad ) + { + debug_error("failed to get sink pad from textoverlay"); + goto ERROR; + } + + /* link new pad with textoverlay first */ + if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) ) + { + debug_error("failed to get pad from sinkbin\n"); + goto ERROR; + } + + gst_object_unref(sinkpad); + sinkpad = NULL; + + /* alright, override pad to textbin.src for futher link */ + pad = gst_element_get_static_pad( + GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst), + "src" ); + if ( ! pad ) + { + debug_error("failed to get sink pad from textoverlay"); + goto ERROR; + } + } + else + { + debug_error("should not reach here."); + goto ERROR; + } + } + + sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "sink" ); + if ( !sinkpad ) + { + debug_error("failed to get pad from sinkbin\n"); + goto ERROR; + } + } + else if (strstr(name, "text")) + { + if (player->pipeline->textbin == NULL) + { + MMPlayerGstElement* mainbin = NULL; + + if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) + { + debug_error("failed to create textbin. continuing without text\n"); + goto ERROR; + } + + sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst; + debug_log("creating textsink bin success\n"); + + /* FIXIT : track number shouldn't be hardcoded */ + mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1); + + player->textsink_linked = 1; + debug_msg("player->textsink_linked set to 1\n"); + + sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "text_sink" ); + if ( !sinkpad ) + { + debug_error("failed to get pad from sinkbin\n"); + goto ERROR; + } + + mainbin = player->pipeline->mainbin; + + if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) + { + /* input selector */ + text_selector = gst_element_factory_make("input-selector", "subtitle_inselector"); + if ( !text_selector ) + { + debug_error ( "failed to create subtitle input selector element\n" ); + goto ERROR; + } + g_object_set (text_selector, "sync-streams", TRUE, NULL); + + mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR; + mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector; + + /* warm up */ + if (GST_STATE_CHANGE_FAILURE == gst_element_set_state (text_selector, GST_STATE_READY)) + { + debug_error("failed to set state(READY) to sinkbin\n"); + goto ERROR; + } + + if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) + { + debug_warning("failed to add subtitle input selector\n"); + goto ERROR; + } + + debug_log ("created element input-selector"); + + } + else + { + debug_log ("already having subtitle input selector"); + text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst; + } + } + + else + { + if (!player->textsink_linked) + { + debug_log("re-using textbin\n"); + + reusing = TRUE; + sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst; + + player->textsink_linked = 1; + debug_msg("player->textsink_linked set to 1\n"); + } + else + { + debug_log("ignoring internal subtutle since external subtitle is available"); + } + } + } + else + { + debug_warning("unknown type of elementary stream! ignoring it...\n"); + goto ERROR; + } + + if ( sinkbin ) + { + if(!reusing) + { + /* warm up */ + if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state( sinkbin, GST_STATE_READY ) ) + { + debug_error("failed to set state(READY) to sinkbin\n"); + goto ERROR; + } + + /* Added for multi audio support to avoid adding audio bin again*/ + /* add */ + if ( FALSE == gst_bin_add( GST_BIN(pipeline), sinkbin ) ) + { + debug_error("failed to add sinkbin to pipeline\n"); + goto ERROR; + } + } + + /* link */ + if (GST_PAD_LINK_OK != GST_PAD_LINK (pad, sinkpad)) + { + debug_error("failed to get pad from sinkbin\n"); + goto ERROR; + } + + if (!reusing) + { + /* run */ + if (GST_STATE_CHANGE_FAILURE == gst_element_set_state (sinkbin, GST_STATE_PAUSED)) + { + debug_error("failed to set state(PAUSED) to sinkbin\n"); + goto ERROR; + } + + if (text_selector) + { + if (GST_STATE_CHANGE_FAILURE == gst_element_set_state (text_selector, GST_STATE_PAUSED)) + { + debug_error("failed to set state(PAUSED) to sinkbin\n"); + goto ERROR; + } + } + } + + gst_object_unref (sinkpad); + sinkpad = NULL; + } + + debug_log ("linking sink bin success\n"); + + /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in + * streaming task. if the task blocked, then buffer will not flow to the next element + * ( autoplugging element ). so this is special hack for streaming. please try to remove it + */ + /* dec stream count. we can remove fakesink if it's zero */ + if (player->num_dynamic_pad) + player->num_dynamic_pad--; + + debug_log ("no more pads: %d stream count dec : %d (num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad); + + if ((player->no_more_pad) && (player->num_dynamic_pad == 0)) + { + __mmplayer_pipeline_complete (NULL, player); + } + + /* FIXIT : please leave a note why this code is needed */ + if(MMPLAYER_IS_WFD_STREAMING( player )) + { + player->no_more_pad = TRUE; + } + +ERROR: + + MMPLAYER_FREEIF(caps_str); + + if ( caps ) + gst_caps_unref( caps ); + + if ( sinkpad ) + gst_object_unref(GST_OBJECT(sinkpad)); + + /* flusing out new attributes */ + if ( mmf_attrs_commit ( attrs ) ) + { + debug_error("failed to comit attributes\n"); + } + + return; +} + +static gboolean +__mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value) +{ + int pro_value = 0; // in the case of expection, default will be returned. + int dest_angle = rotation_angle; + int rotation_type = -1; + #define ROTATION_USING_SINK 0 + #define ROTATION_USING_CUSTOM 1 + #define ROTATION_USING_FLIP 2 + + return_val_if_fail(player, FALSE); + return_val_if_fail(value, FALSE); + return_val_if_fail(rotation_angle >= 0, FALSE); + + if (rotation_angle >= 360) + { + dest_angle = rotation_angle - 360; + } + + /* chech if supported or not */ + if ( dest_angle % 90 ) + { + debug_log("not supported rotation angle = %d", rotation_angle); + return FALSE; + } + + /* + * xvimagesink only (A) + * custom_convert - no xv (e.g. memsink, evasimagesink (B) + * videoflip - avsysmemsink (C) + */ + if (player->set_mode.video_zc) + { + if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B + { + rotation_type = ROTATION_USING_CUSTOM; + } + else // A + { + rotation_type = ROTATION_USING_SINK; + } + } + else + { + int surface_type = 0; + rotation_type = ROTATION_USING_FLIP; + + mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type); + debug_log("check display surface type attribute: %d", surface_type); + + if ((surface_type == MM_DISPLAY_SURFACE_X) || + (surface_type == MM_DISPLAY_SURFACE_EVAS && !strcmp(player->ini.videosink_element_evas, "evaspixmapsink"))) + { + rotation_type = ROTATION_USING_SINK; + } + else + { + rotation_type = ROTATION_USING_FLIP; //C + } + + debug_log("using %d type for rotation", rotation_type); + } + + /* get property value for setting */ + switch(rotation_type) + { + case ROTATION_USING_SINK: // xvimagesink, pixmap + { + switch (dest_angle) + { + case 0: + break; + case 90: + pro_value = 3; // clockwise 90 + break; + case 180: + pro_value = 2; + break; + case 270: + pro_value = 1; // counter-clockwise 90 + break; + } + } + break; + case ROTATION_USING_CUSTOM: + { + gchar *ename = NULL; + ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst)); + + if (g_strrstr(ename, "fimcconvert")) + { + switch (dest_angle) + { + case 0: + break; + case 90: + pro_value = 90; // clockwise 90 + break; + case 180: + pro_value = 180; + break; + case 270: + pro_value = 270; // counter-clockwise 90 + break; + } + } + } + break; + case ROTATION_USING_FLIP: // videoflip + { + switch (dest_angle) + { + + case 0: + break; + case 90: + pro_value = 1; // clockwise 90 + break; + case 180: + pro_value = 2; + break; + case 270: + pro_value = 3; // counter-clockwise 90 + break; + } + } + break; + } + + debug_log("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type); + + *value = pro_value; + + return TRUE; +} + +int +_mmplayer_update_video_param(mm_player_t* player) // @ +{ + MMHandleType attrs = 0; + int surface_type = 0; + int org_angle = 0; // current supported angle values are 0, 90, 180, 270 + int user_angle = 0; + int user_angle_type= 0; + int rotation_value = 0; + gchar *org_orient = NULL; + + MMPLAYER_FENTER(); + + /* check video sinkbin is created */ + return_val_if_fail ( player && + player->pipeline && + player->pipeline->videobin && + player->pipeline->videobin[MMPLAYER_V_BIN].gst && + player->pipeline->videobin[MMPLAYER_V_SINK].gst, + MM_ERROR_PLAYER_NOT_INITIALIZED ); + + attrs = MMPLAYER_GET_ATTRS(player); + if ( !attrs ) + { + debug_error("cannot get content attribute"); + return MM_ERROR_PLAYER_INTERNAL; + } + + /* update user roation */ + mm_attrs_get_int_by_name(attrs, "display_rotation", &user_angle_type); + + /* get angle with user type */ + switch(user_angle_type) + { + case MM_DISPLAY_ROTATION_NONE: + user_angle = 0; + break; + case MM_DISPLAY_ROTATION_90: // counter-clockwise 90 + user_angle = 270; + break; + case MM_DISPLAY_ROTATION_180: + user_angle = 180; + break; + case MM_DISPLAY_ROTATION_270: // clockwise 90 + user_angle = 90; + break; + } + + /* get original orientation */ + mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient); + + if (org_orient) + { + if (!strcmp (org_orient, "rotate-90")) + org_angle = 90; + else if (!strcmp (org_orient, "rotate-180")) + org_angle = 180; + else if (!strcmp (org_orient, "rotate-270")) + org_angle = 270; + else + debug_log ("original rotation is %s", org_orient); + } + else + { + debug_log ("content_video_orientation get fail"); + } + + debug_log("check user angle: %d, orientation: %d", user_angle, org_angle); + + /* check video stream callback is used */ + if(!player->set_mode.media_packet_video_stream && player->use_video_stream ) + { + if (player->set_mode.video_zc) + { + gchar *ename = NULL; + int width = 0; + int height = 0; + + mm_attrs_get_int_by_name(attrs, "display_width", &width); + mm_attrs_get_int_by_name(attrs, "display_height", &height); + + /* resize video frame with requested values for fimcconvert */ + ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst)); + + if (ename && g_strrstr(ename, "fimcconvert")) + { + if (width) + g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-width", width, NULL); + + if (height) + g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-height", height, NULL); + + /* NOTE: fimcconvert does not manage index of src buffer from upstream src-plugin, decoder gives frame information in output buffer with no ordering */ + g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "src-rand-idx", TRUE, NULL); + + /* get rotation value to set */ + __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value); + + g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "rotate", rotation_value, NULL); + + debug_log("updating fimcconvert - r[%d], w[%d], h[%d]", rotation_value, width, height); + } + } + else + { + debug_log("using video stream callback with memsink. player handle : [%p]", player); + + /* get rotation value to set */ + __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value); + + g_object_set(player->pipeline->videobin[MMPLAYER_V_FLIP].gst, "method", rotation_value, NULL); + } + + return MM_ERROR_NONE; + } + + /* update display surface */ + mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type); + debug_log("check display surface type attribute: %d", surface_type); + + /* configuring display */ + switch ( surface_type ) + { + case MM_DISPLAY_SURFACE_X: + { + /* ximagesink or xvimagesink */ + void *surface = NULL; + int display_method = 0; + int roi_x = 0; + int roi_y = 0; + int roi_w = 0; + int roi_h = 0; + int src_crop_x = 0; + int src_crop_y = 0; + int src_crop_w = 0; + int src_crop_h = 0; + int force_aspect_ratio = 0; + gboolean visible = TRUE; + +#ifdef HAVE_WAYLAND + /*set wl_display*/ + void* wl_display = NULL; + GstContext *context = NULL; + int wl_window_x = 0; + int wl_window_y = 0; + int wl_window_width = 0; + int wl_window_height = 0; + + mm_attrs_get_data_by_name(attrs, "wl_display", &wl_display); + if (wl_display) + context = gst_wayland_display_handle_context_new(wl_display); + if (context) + gst_element_set_context(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), context); + + /*It should be set after setting window*/ + mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x); + mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y); + mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width); + mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height); +#endif + /* common case if using x surface */ + mm_attrs_get_data_by_name(attrs, "display_overlay", &surface); + if ( surface ) + { +#ifdef HAVE_WAYLAND + guintptr wl_surface = (guintptr)surface; + debug_log("set video param : wayland surface %p", surface); + gst_video_overlay_set_window_handle( + GST_VIDEO_OVERLAY( player->pipeline->videobin[MMPLAYER_V_SINK].gst ), + wl_surface ); + /* After setting window handle, set render rectangle */ + gst_video_overlay_set_render_rectangle( + GST_VIDEO_OVERLAY( player->pipeline->videobin[MMPLAYER_V_SINK].gst ), + wl_window_x,wl_window_y,wl_window_width,wl_window_height); +#else // HAVE_X11 + int xwin_id = 0; + xwin_id = *(int*)surface; + debug_log("set video param : xid %p", *(int*)surface); + if (xwin_id) + { + gst_video_overlay_set_window_handle( GST_VIDEO_OVERLAY( player->pipeline->videobin[MMPLAYER_V_SINK].gst ), *(int*)surface ); + } +#endif + } + else + { + /* FIXIT : is it error case? */ + debug_warning("still we don't have xid on player attribute. create it's own surface."); + } + + /* if xvimagesink */ + if (!strcmp(player->ini.videosink_element_x,"xvimagesink")) + { + mm_attrs_get_int_by_name(attrs, "display_force_aspect_ration", &force_aspect_ratio); + mm_attrs_get_int_by_name(attrs, "display_method", &display_method); + mm_attrs_get_int_by_name(attrs, "display_src_crop_x", &src_crop_x); + mm_attrs_get_int_by_name(attrs, "display_src_crop_y", &src_crop_y); + mm_attrs_get_int_by_name(attrs, "display_src_crop_width", &src_crop_w); + mm_attrs_get_int_by_name(attrs, "display_src_crop_height", &src_crop_h); + mm_attrs_get_int_by_name(attrs, "display_roi_x", &roi_x); + mm_attrs_get_int_by_name(attrs, "display_roi_y", &roi_y); + mm_attrs_get_int_by_name(attrs, "display_roi_width", &roi_w); + mm_attrs_get_int_by_name(attrs, "display_roi_height", &roi_h); + mm_attrs_get_int_by_name(attrs, "display_visible", &visible); + #define DEFAULT_DISPLAY_MODE 2 // TV only, PRI_VIDEO_OFF_AND_SEC_VIDEO_FULL_SCREEN + + /* setting for cropping media source */ + if (src_crop_w && src_crop_h) + { + g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, + "src-crop-x", src_crop_x, + "src-crop-y", src_crop_y, + "src-crop-w", src_crop_w, + "src-crop-h", src_crop_h, + NULL ); + } + + /* setting for ROI mode */ + if (display_method == 5) // 5 for ROI mode + { + int roi_mode = 0; + mm_attrs_get_int_by_name(attrs, "display_roi_mode", &roi_mode); + g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, + "dst-roi-mode", roi_mode, + "dst-roi-x", roi_x, + "dst-roi-y", roi_y, + "dst-roi-w", roi_w, + "dst-roi-h", roi_h, + NULL ); + /* get rotation value to set, + do not use org_angle because ROI mode in xvimagesink needs both a rotation value and an orientation value */ + __mmplayer_get_property_value_for_rotation(player, user_angle, &rotation_value); + } + else + { + /* get rotation value to set */ + __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value); + } + + g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, + "force-aspect-ratio", force_aspect_ratio, + "orientation", org_angle/90, // setting for orientation of media, it is used for ROI/ZOOM feature in xvimagesink + "rotate", rotation_value, + "handle-events", TRUE, + "display-geometry-method", display_method, + "draw-borders", FALSE, + "handle-expose", FALSE, + "visible", visible, + "display-mode", DEFAULT_DISPLAY_MODE, + NULL ); + + debug_log("set video param : rotate %d, method %d visible %d", rotation_value, display_method, visible); + debug_log("set video param : dst-roi-x: %d, dst-roi-y: %d, dst-roi-w: %d, dst-roi-h: %d", roi_x, roi_y, roi_w, roi_h ); + debug_log("set video param : force aspect ratio %d, display mode %d", force_aspect_ratio, DEFAULT_DISPLAY_MODE); + } + } + break; + case MM_DISPLAY_SURFACE_EVAS: + { + void *object = NULL; + int scaling = 0; + gboolean visible = TRUE; + int display_method = 0; + + /* common case if using evas surface */ + mm_attrs_get_data_by_name(attrs, "display_overlay", &object); + mm_attrs_get_int_by_name(attrs, "display_visible", &visible); + mm_attrs_get_int_by_name(attrs, "display_evas_do_scaling", &scaling); + mm_attrs_get_int_by_name(attrs, "display_method", &display_method); + + /* if evasimagesink */ + if (!strcmp(player->ini.videosink_element_evas,"evasimagesink")) + { + if (object) + { + /* if it is evasimagesink, we are not supporting rotation */ + if (user_angle_type!=MM_DISPLAY_ROTATION_NONE) + { + mm_attrs_set_int_by_name(attrs, "display_rotation", MM_DISPLAY_ROTATION_NONE); + if (mmf_attrs_commit (attrs)) /* return -1 if error */ + debug_error("failed to commit\n"); + debug_warning("unsupported feature"); + return MM_ERROR_NOT_SUPPORT_API; + } + __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value); + g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, + "evas-object", object, + "visible", visible, + "display-geometry-method", display_method, + "rotate", rotation_value, + NULL); + debug_log("set video param : method %d", display_method); + debug_log("set video param : evas-object %x, visible %d", object, visible); + debug_log("set video param : evas-object %x, rotate %d", object, rotation_value); + } + else + { + debug_error("no evas object"); + return MM_ERROR_PLAYER_INTERNAL; + } + + + /* if evasimagesink using converter */ + if (player->set_mode.video_zc && player->pipeline->videobin[MMPLAYER_V_CONV].gst) + { + int width = 0; + int height = 0; + int no_scaling = !scaling; + + mm_attrs_get_int_by_name(attrs, "display_width", &width); + mm_attrs_get_int_by_name(attrs, "display_height", &height); + + /* NOTE: fimcconvert does not manage index of src buffer from upstream src-plugin, decoder gives frame information in output buffer with no ordering */ + g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "src-rand-idx", TRUE, NULL); + g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-buffer-num", 5, NULL); + + if (no_scaling) + { + /* no-scaling order to fimcconvert, original width, height size of media src will be passed to sink plugin */ + g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, + "dst-width", 0, /* setting 0, output video width will be media src's width */ + "dst-height", 0, /* setting 0, output video height will be media src's height */ + NULL); + } + else + { + /* scaling order to fimcconvert */ + if (width) + { + g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-width", width, NULL); + } + if (height) + { + g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-height", height, NULL); + } + debug_log("set video param : video frame scaling down to width(%d) height(%d)", width, height); + } + debug_log("set video param : display_evas_do_scaling %d", scaling); + } + } + + /* if evaspixmapsink */ + if (!strcmp(player->ini.videosink_element_evas,"evaspixmapsink")) + { + if (object) + { + __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value); + g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, + "evas-object", object, + "visible", visible, + "display-geometry-method", display_method, + "rotate", rotation_value, + NULL); + debug_log("set video param : method %d", display_method); + debug_log("set video param : evas-object %x, visible %d", object, visible); + debug_log("set video param : evas-object %x, rotate %d", object, rotation_value); + } + else + { + debug_error("no evas object"); + return MM_ERROR_PLAYER_INTERNAL; + } + + int display_method = 0; + int roi_x = 0; + int roi_y = 0; + int roi_w = 0; + int roi_h = 0; + int origin_size = !scaling; + + mm_attrs_get_int_by_name(attrs, "display_method", &display_method); + mm_attrs_get_int_by_name(attrs, "display_roi_x", &roi_x); + mm_attrs_get_int_by_name(attrs, "display_roi_y", &roi_y); + mm_attrs_get_int_by_name(attrs, "display_roi_width", &roi_w); + mm_attrs_get_int_by_name(attrs, "display_roi_height", &roi_h); + + /* get rotation value to set */ + __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value); + + g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, + "origin-size", origin_size, + "rotate", rotation_value, + "dst-roi-x", roi_x, + "dst-roi-y", roi_y, + "dst-roi-w", roi_w, + "dst-roi-h", roi_h, + "display-geometry-method", display_method, + NULL ); + + debug_log("set video param : method %d", display_method); + debug_log("set video param : dst-roi-x: %d, dst-roi-y: %d, dst-roi-w: %d, dst-roi-h: %d", + roi_x, roi_y, roi_w, roi_h ); + debug_log("set video param : display_evas_do_scaling %d (origin-size %d)", scaling, origin_size); + } + } + break; + case MM_DISPLAY_SURFACE_X_EXT: /* NOTE : this surface type is used for the videoTexture(canvasTexture) overlay */ + { + void *pixmap_id_cb = NULL; + void *pixmap_id_cb_user_data = NULL; + int display_method = 0; + gboolean visible = TRUE; + + /* if xvimagesink */ + if (strcmp(player->ini.videosink_element_x,"xvimagesink")) + { + debug_error("videosink is not xvimagesink"); + return MM_ERROR_PLAYER_INTERNAL; + } + + /* get information from attributes */ + mm_attrs_get_data_by_name(attrs, "display_overlay", &pixmap_id_cb); + mm_attrs_get_data_by_name(attrs, "display_overlay_user_data", &pixmap_id_cb_user_data); + mm_attrs_get_int_by_name(attrs, "display_method", &display_method); + mm_attrs_get_int_by_name(attrs, "display_visible", &visible); + + if ( pixmap_id_cb ) + { + debug_log("set video param : display_overlay(0x%x)", pixmap_id_cb); + if (pixmap_id_cb_user_data) + { + debug_log("set video param : display_overlay_user_data(0x%x)", pixmap_id_cb_user_data); + } + } + else + { + debug_error("failed to set pixmap-id-callback"); + return MM_ERROR_PLAYER_INTERNAL; + } + /* get rotation value to set */ + __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value); + + debug_log("set video param : rotate %d, method %d, visible %d", rotation_value, display_method, visible); + + /* set properties of videosink plugin */ + g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, + "display-geometry-method", display_method, + "draw-borders", FALSE, + "visible", visible, + "rotate", rotation_value, + "pixmap-id-callback", pixmap_id_cb, + "pixmap-id-callback-userdata", pixmap_id_cb_user_data, + NULL ); + } + break; + case MM_DISPLAY_SURFACE_NULL: + { + /* do nothing */ + } + break; + case MM_DISPLAY_SURFACE_REMOTE: + { + /* do nothing */ + } + break; + } + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +static int +__mmplayer_gst_element_link_bucket(GList* element_bucket) // @ +{ + GList* bucket = element_bucket; + MMPlayerGstElement* element = NULL; + MMPlayerGstElement* prv_element = NULL; + gint successful_link_count = 0; + + MMPLAYER_FENTER(); + + return_val_if_fail(element_bucket, -1); + + prv_element = (MMPlayerGstElement*)bucket->data; + bucket = bucket->next; + + for ( ; bucket; bucket = bucket->next ) + { + element = (MMPlayerGstElement*)bucket->data; + + if ( element && element->gst ) + { + /* If next element is audio appsrc then make a seprate audio pipeline */ + if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),"audio_appsrc") || + !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),"subtitle_appsrc")) + { + prv_element = element; + continue; + } + + if ( GST_ELEMENT_LINK(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst)) ) + { + debug_log("linking [%s] to [%s] success\n", + GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)), + GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) ); + successful_link_count ++; + } + else + { + debug_log("linking [%s] to [%s] failed\n", + GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)), + GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) ); + return -1; + } + } + + prv_element = element; + } + + MMPLAYER_FLEAVE(); + + return successful_link_count; +} + +static int +__mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket) // @ +{ + GList* bucket = element_bucket; + MMPlayerGstElement* element = NULL; + int successful_add_count = 0; + + MMPLAYER_FENTER(); + + return_val_if_fail(element_bucket, 0); + return_val_if_fail(bin, 0); + + for ( ; bucket; bucket = bucket->next ) + { + element = (MMPlayerGstElement*)bucket->data; + + if ( element && element->gst ) + { + if( !gst_bin_add(bin, GST_ELEMENT(element->gst)) ) + { + debug_log("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n", + GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), + GST_ELEMENT_NAME(GST_ELEMENT(bin) ) ); + return 0; + } + successful_add_count ++; + } + } + + MMPLAYER_FLEAVE(); + + return successful_add_count; +} + +static void __mmplayer_gst_caps_notify_cb (GstPad * pad, GParamSpec * unused, gpointer data) +{ + mm_player_t* player = (mm_player_t*) data; + GstCaps *caps = NULL; + GstStructure *str = NULL; + const char *name; + + MMPLAYER_FENTER(); + + return_if_fail ( pad ) + return_if_fail ( unused ) + return_if_fail ( data ) + + caps = gst_pad_query_caps(pad, NULL); + if ( !caps ) + { + return; + } + + str = gst_caps_get_structure(caps, 0); + if ( !str ) + { + goto ERROR; + } + + name = gst_structure_get_name(str); + if ( !name ) + { + goto ERROR; + } + + debug_log("name = %s\n", name); + + if (strstr(name, "audio")) + { + _mmplayer_update_content_attrs (player, ATTR_AUDIO); + + if (player->audio_stream_changed_cb) + { + debug_error("call the audio stream changed cb\n"); + player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param); + } + } + else if (strstr(name, "video")) + { + _mmplayer_update_content_attrs (player, ATTR_VIDEO); + + if (player->video_stream_changed_cb) + { + debug_error("call the video stream changed cb\n"); + player->video_stream_changed_cb(player->video_stream_changed_cb_user_param); + } + } + else + { + goto ERROR; + } + +ERROR: + + gst_caps_unref(caps); + + MMPLAYER_FLEAVE(); + + return; +} + + + +/** + * This function is to create audio pipeline for playing. + * + * @param player [in] handle of player + * + * @return This function returns zero on success. + * @remark + * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline + */ +#define MMPLAYER_CREATEONLY_ELEMENT(x_bin, x_id, x_factory, x_name) \ +x_bin[x_id].id = x_id;\ +x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\ +if ( ! x_bin[x_id].gst )\ +{\ + debug_error("failed to create %s \n", x_factory);\ + goto ERROR;\ +}\ + +#define MMPLAYER_CREATE_ELEMENT_ADD_BIN(x_bin, x_id, x_factory, x_name, y_bin, x_player) \ +x_bin[x_id].id = x_id;\ +x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\ +if ( ! x_bin[x_id].gst )\ +{\ + debug_error("failed to create %s \n", x_factory);\ + goto ERROR;\ +}\ +else\ +{\ + if (x_player->ini.set_dump_element_flag)\ + __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\ +}\ +if( !gst_bin_add(GST_BIN(y_bin), GST_ELEMENT(x_bin[x_id].gst)))\ +{\ + debug_log("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",\ + GST_ELEMENT_NAME(GST_ELEMENT(x_bin[x_id].gst)),\ + GST_ELEMENT_NAME(GST_ELEMENT(y_bin) ) );\ + goto ERROR;\ +}\ + +/* macro for code readability. just for sinkbin-creation functions */ +#define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \ +do \ +{ \ + x_bin[x_id].id = x_id;\ + x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\ + if ( ! x_bin[x_id].gst )\ + {\ + debug_error("failed to create %s \n", x_factory);\ + goto ERROR;\ + }\ + else\ + {\ + if (x_player->ini.set_dump_element_flag)\ + __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\ + }\ + if ( x_add_bucket )\ + element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\ +} while(0); + +static void +__mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data) +{ + mm_player_t* player = (mm_player_t*) data; + + gint channel = 0; + gint rate = 0; + gint depth = 0; + gint endianness = 0; + guint64 channel_mask = 0; + + MMPlayerAudioStreamDataType audio_stream = { 0, }; + GstMapInfo mapinfo = GST_MAP_INFO_INIT; + + MMPLAYER_FENTER(); + return_if_fail(player->audio_stream_render_cb_ex); + + debug_log ("__mmplayer_audio_stream_decoded_render_cb new pad: %s", GST_PAD_NAME (pad)); + + gst_buffer_map(buffer, &mapinfo, GST_MAP_READ); + audio_stream.data = mapinfo.data; + audio_stream.data_size = mapinfo.size; + + GstCaps *caps = gst_pad_get_current_caps( pad ); + GstStructure *structure = gst_caps_get_structure (caps, 0); + + MMPLAYER_LOG_GST_CAPS_TYPE(caps); + gst_structure_get_int (structure, "rate", &rate); + gst_structure_get_int (structure, "channels", &channel); + gst_structure_get_int (structure, "depth", &depth); + gst_structure_get_int (structure, "endianness", &endianness); + gst_structure_get (structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL); + + gst_caps_unref(GST_CAPS(caps)); + + audio_stream.bitrate = rate; + audio_stream.channel = channel; + audio_stream.depth = depth; + audio_stream.is_little_endian = (endianness == 1234 ? 1 : 0); + audio_stream.channel_mask = channel_mask; + debug_log ("bitrate : %d channel : %d depth: %d ls_little_endian : %d channel_mask: %d, %p", rate, channel, depth, endianness, channel_mask, player->audio_stream_cb_user_param); + player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param); + gst_buffer_unmap(buffer, &mapinfo); + + MMPLAYER_FLEAVE(); +} + +static void +__mmplayer_gst_audio_deinterleave_pad_added (GstElement *elem, GstPad *pad, gpointer data) +{ + mm_player_t* player = (mm_player_t*)data; + MMPlayerGstElement* audiobin = player->pipeline->audiobin; + GstPad* sinkpad = NULL; + GstElement *queue = NULL, *sink = NULL; + + MMPLAYER_FENTER(); + return_if_fail (player && player->pipeline && player->pipeline->mainbin); + + queue = gst_element_factory_make ("queue", NULL); + if (queue == NULL) + { + debug_log ("fail make queue\n"); + goto ERROR; + } + + sink = gst_element_factory_make ("fakesink", NULL); + if (sink == NULL) + { + debug_log ("fail make fakesink\n"); + goto ERROR; + } + + gst_bin_add_many (GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL); + + if (!gst_element_link_pads_full (queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) + { + debug_warning("failed to link queue & sink\n"); + goto ERROR; + } + + sinkpad = gst_element_get_static_pad (queue, "sink"); + + if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) + { + debug_warning ("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad)); + goto ERROR; + } + + debug_error("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync); + + gst_object_unref (sinkpad); + g_object_set (sink, "sync", player->audio_stream_sink_sync, NULL); + g_object_set (sink, "signal-handoffs", TRUE, NULL); + + gst_element_set_state (sink, GST_STATE_PAUSED); + gst_element_set_state (queue, GST_STATE_PAUSED); + + MMPLAYER_SIGNAL_CONNECT( player, + G_OBJECT(sink), + MM_PLAYER_SIGNAL_TYPE_AUDIOBIN, + "handoff", + G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb), + (gpointer)player ); + + MMPLAYER_FLEAVE(); + return ; + +ERROR: + debug_error("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n"); + if (queue) + { + gst_object_unref(GST_OBJECT(queue)); + queue = NULL; + } + if (sink) + { + gst_object_unref(GST_OBJECT(sink)); + sink = NULL; + } + if (sinkpad) + { + gst_object_unref ( GST_OBJECT(sinkpad) ); + sinkpad = NULL; + } + + return; +} + +void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs) +{ + #define MAX_PROPS_LEN 64 + gint volume_type = 0; + gint latency_mode = 0; + gchar *stream_type = NULL; + gchar *latency = NULL; + gint stream_id = 0; + gchar stream_props[MAX_PROPS_LEN] = {0,}; + GstStructure *props = NULL; + + /* set volume table + * It should be set after player creation through attribute. + * But, it can not be changed during playing. + */ + MMPLAYER_FENTER(); + mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id); + mm_attrs_get_string_by_name (attrs, "sound_stream_type", &stream_type ); + + if ( stream_id < 1 || !stream_type || strlen(stream_type) < 1) + { + debug_error("stream_id[%d] or stream_type[%s] is not valid.\n", stream_id, stream_type); + } + else + { + snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d", stream_type, stream_id); + props = gst_structure_from_string(stream_props, NULL); + g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL); + debug_log("stream_id[%d], stream_type[%s], result[%s].\n", stream_id, stream_type, stream_props); + } + + mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode); + mm_attrs_get_int_by_name(attrs, "sound_volume_type", &volume_type); + + switch (latency_mode) + { + case AUDIO_LATENCY_MODE_LOW: + latency = g_strndup("low", 3); + break; + case AUDIO_LATENCY_MODE_MID: + latency = g_strndup("mid", 3); + break; + case AUDIO_LATENCY_MODE_HIGH: + latency = g_strndup("high", 4); + break; + }; + + /* hook sound_type if emergency case */ + if (player->sound_focus.focus_changed_msg == MM_PLAYER_FOCUS_CHANGED_BY_EMERGENCY) + { + debug_log ("emergency session, hook sound_type from [%d] to [%d]\n", volume_type, MM_SOUND_VOLUME_TYPE_EMERGENCY); + volume_type = MM_SOUND_VOLUME_TYPE_EMERGENCY; + } +#if 0 //need to check + if (player->sound_focus.user_route_policy != 0) + { + route_path = player->sound_focus.user_route_policy; + } + + g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, + "latency", latency_mode, + NULL); + + debug_log("audiosink property status...volume type:%d, user-route=%d, latency=%d \n", + volume_type, route_path, latency_mode); + MMPLAYER_FLEAVE(); + +#endif + + g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, + "latency", latency, + NULL); + + debug_log("audiosink property - volume type=%d, latency=%s \n", + volume_type, latency); + + g_free(latency); + + MMPLAYER_FLEAVE(); +} + +static int +__mmplayer_gst_create_audio_pipeline(mm_player_t* player) +{ + MMPlayerGstElement* first_element = NULL; + MMPlayerGstElement* audiobin = NULL; + MMHandleType attrs = 0; + GstPad *pad = NULL; + GstPad *ghostpad = NULL; + GList* element_bucket = NULL; + gboolean link_audio_sink_now = TRUE; + int i =0; + + MMPLAYER_FENTER(); + + return_val_if_fail( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + /* alloc handles */ + audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM); + if ( ! audiobin ) + { + debug_error("failed to allocate memory for audiobin\n"); + return MM_ERROR_PLAYER_NO_FREE_SPACE; + } + + attrs = MMPLAYER_GET_ATTRS(player); + + /* create bin */ + audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN; + audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin"); + if ( !audiobin[MMPLAYER_A_BIN].gst ) + { + debug_error("failed to create audiobin\n"); + goto ERROR; + } + + /* take it */ + player->pipeline->audiobin = audiobin; + + player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player); + + /* Adding audiotp plugin for reverse trickplay feature */ +// MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player); + + /* converter */ + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player); + + /* resampler */ + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.name_of_audio_resampler, "audio resampler", TRUE, player); + + if (player->set_mode.pcm_extraction) // pcm extraction only and no sound output + { + if(player->audio_stream_render_cb_ex) + { + char *caps_str = NULL; + GstCaps* caps = NULL; + gchar *format = NULL; + + /* capsfilter */ + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player); + + mm_attrs_get_string_by_name (player->attrs, "pcm_audioformat", &format ); + + debug_log("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel); + + caps = gst_caps_new_simple ("audio/x-raw", + "format", G_TYPE_STRING, format, + "rate", G_TYPE_INT, player->pcm_samplerate, + "channels", G_TYPE_INT, player->pcm_channel, + NULL); + caps_str = gst_caps_to_string(caps); + debug_log("new caps : %s\n", caps_str); + + g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL ); + + /* clean */ + gst_caps_unref( caps ); + MMPLAYER_FREEIF( caps_str ); + + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player); + + g_object_set (G_OBJECT (audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL); + /* raw pad handling signal */ + MMPLAYER_SIGNAL_CONNECT( player, + (audiobin[MMPLAYER_A_DEINTERLEAVE].gst), + MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", + G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player); + } + else + { + int dst_samplerate = 0; + int dst_channels = 0; + int dst_depth = 0; + char *caps_str = NULL; + GstCaps* caps = NULL; + + /* get conf. values */ + mm_attrs_multiple_get(player->attrs, + NULL, + "pcm_extraction_samplerate", &dst_samplerate, + "pcm_extraction_channels", &dst_channels, + "pcm_extraction_depth", &dst_depth, + NULL); + + /* capsfilter */ + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player); + caps = gst_caps_new_simple ("audio/x-raw", + "rate", G_TYPE_INT, dst_samplerate, + "channels", G_TYPE_INT, dst_channels, + "depth", G_TYPE_INT, dst_depth, + NULL); + caps_str = gst_caps_to_string(caps); + debug_log("new caps : %s\n", caps_str); + + g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL ); + + /* clean */ + gst_caps_unref( caps ); + MMPLAYER_FREEIF( caps_str ); + + /* fake sink */ + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player); + + /* set sync */ + g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL); + } + } + else // normal playback + { + //GstCaps* caps = NULL; + gint channels = 0; + + /* for logical volume control */ + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player); + g_object_set(G_OBJECT (audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL); + + if (player->sound.mute) + { + debug_log("mute enabled\n"); + g_object_set(G_OBJECT (audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL); + } + +#if 0 + /*capsfilter */ + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player); + caps = gst_caps_from_string( "audio/x-raw-int, " + "endianness = (int) LITTLE_ENDIAN, " + "signed = (boolean) true, " + "width = (int) 16, " + "depth = (int) 16" ); + g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL ); + gst_caps_unref( caps ); +#endif + + /* chech if multi-chennels */ + if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) + { + GstPad *srcpad = NULL; + GstCaps *caps = NULL; + + if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) + { + if ((caps = gst_pad_query_caps(srcpad, NULL))) + { + //MMPLAYER_LOG_GST_CAPS_TYPE(caps); + GstStructure *str = gst_caps_get_structure(caps, 0); + if (str) + gst_structure_get_int (str, "channels", &channels); + gst_caps_unref(caps); + } + gst_object_unref(srcpad); + } + } + + /* audio effect element. if audio effect is enabled */ + if ( (strcmp(player->ini.name_of_audio_effect, "")) + && (channels <= 2) + && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom) ) + { + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.name_of_audio_effect, "audio effect filter", TRUE, player); + + debug_log("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type); + + if ( (!player->bypass_audio_effect) + && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom) ) + { + if ( MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type ) + { + if (!_mmplayer_audio_effect_custom_apply(player)) + { + debug_msg("apply audio effect(custom) setting success\n"); + } + } + } + + if ( (strcmp(player->ini.name_of_audio_effect_sec, "")) + && (player->set_mode.rich_audio) ) + { + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.name_of_audio_effect_sec, "audio effect filter", TRUE, player); + } + } + if (!MMPLAYER_IS_RTSP_STREAMING(player)) + { + if (player->set_mode.rich_audio && channels <= 2) + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VSP, "audiovsp", "x-speed", TRUE, player); + } + + /* create audio sink */ + MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.name_of_audiosink, "audiosink", link_audio_sink_now, player); + + /* qos on */ + g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */ + g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL); + + /* FIXIT : using system clock. isn't there another way? */ + if (player->videodec_linked) + { + debug_log("provide clock for movie = %s", (player->ini.provide_clock_for_movie)?"audio_clock":"sys_clock"); + g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "provide-clock", player->ini.provide_clock_for_movie, NULL); + } + else + { + debug_log("provide clock for music = %s", (player->ini.provide_clock_for_music)?"audio_clock":"sys_clock"); + g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "provide-clock", player->ini.provide_clock_for_music, NULL); + } + + if (g_strrstr(player->ini.name_of_audiosink, "pulsesink")) + __mmplayer_gst_set_audiosink_property(player, attrs); + } + + if (audiobin[MMPLAYER_A_SINK].gst) + { + GstPad *sink_pad = NULL; + sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink"); + MMPLAYER_SIGNAL_CONNECT (player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN, + "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player); + gst_object_unref (GST_OBJECT(sink_pad)); + } + + __mmplayer_add_sink( player, audiobin[MMPLAYER_A_SINK].gst ); + + /* adding created elements to bin */ + debug_log("adding created elements to bin\n"); + if( !__mmplayer_gst_element_add_bucket_to_bin( GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket )) + { + debug_error("failed to add elements\n"); + goto ERROR; + } + + /* linking elements in the bucket by added order. */ + debug_log("Linking elements in the bucket by added order.\n"); + if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 ) + { + debug_error("failed to link elements\n"); + goto ERROR; + } + + /* get first element's sinkpad for creating ghostpad */ + first_element = (MMPlayerGstElement *)element_bucket->data; + + pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink"); + if ( ! pad ) + { + debug_error("failed to get pad from first element of audiobin\n"); + goto ERROR; + } + + ghostpad = gst_ghost_pad_new("sink", pad); + if ( ! ghostpad ) + { + debug_error("failed to create ghostpad\n"); + goto ERROR; + } + + if ( FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad) ) + { + debug_error("failed to add ghostpad to audiobin\n"); + goto ERROR; + } + + player->gapless.audio_data_probe_id = gst_pad_add_probe(ghostpad, GST_PAD_PROBE_TYPE_BUFFER, + __mmplayer_audio_data_probe, player, NULL); + + gst_object_unref(pad); + + g_list_free(element_bucket); + + mm_attrs_set_int_by_name(attrs, "content_audio_found", TRUE); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; + +ERROR: + + debug_log("ERROR : releasing audiobin\n"); + + if ( pad ) + gst_object_unref(GST_OBJECT(pad)); + + if ( ghostpad ) + gst_object_unref(GST_OBJECT(ghostpad)); + + g_list_free( element_bucket ); + + /* release element which are not added to bin */ + for ( i = 1; i < MMPLAYER_A_NUM; i++ ) /* NOTE : skip bin */ + { + if ( audiobin[i].gst ) + { + GstObject* parent = NULL; + parent = gst_element_get_parent( audiobin[i].gst ); + + if ( !parent ) + { + gst_object_unref(GST_OBJECT(audiobin[i].gst)); + audiobin[i].gst = NULL; + } + else + { + gst_object_unref(GST_OBJECT(parent)); + } + } + } + + /* release audiobin with it's childs */ + if ( audiobin[MMPLAYER_A_BIN].gst ) + { + gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst)); + } + + MMPLAYER_FREEIF( audiobin ); + + player->pipeline->audiobin = NULL; + + return MM_ERROR_PLAYER_INTERNAL; +} + +static GstPadProbeReturn +__mmplayer_audio_stream_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data) +{ + mm_player_t* player = (mm_player_t*) u_data; + GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info); + GstMapInfo probe_info = GST_MAP_INFO_INIT; + + gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ); + + if (player->audio_stream_cb && probe_info.size && probe_info.data) + player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param); + + return GST_PAD_PROBE_OK; +} + +static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name) +{ + return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24); +} + +static GstPadProbeReturn +__mmplayer_video_stream_probe (GstPad *pad, GstPadProbeInfo *info, gpointer user_data) +{ + GstCaps *caps = NULL; + MMPlayerVideoStreamDataType stream; + MMVideoBuffer *video_buffer = NULL; + GstMemory *dataBlock = NULL; + GstMemory *metaBlock = NULL; + GstMapInfo mapinfo = GST_MAP_INFO_INIT; + GstStructure *structure = NULL; + const gchar *string_format = NULL; + unsigned int fourcc = 0; + mm_player_t* player = (mm_player_t*)user_data; + GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info); + + return_val_if_fail(buffer, GST_PAD_PROBE_DROP); + return_val_if_fail(gst_buffer_n_memory(buffer) , GST_PAD_PROBE_DROP); + + caps = gst_pad_get_current_caps(pad); + if (caps == NULL) { + debug_error( "Caps is NULL." ); + return GST_PAD_PROBE_OK; + } + + MMPLAYER_LOG_GST_CAPS_TYPE(caps); + + /* clear stream data structure */ + memset(&stream, 0x0, sizeof(MMPlayerVideoStreamDataType)); + + structure = gst_caps_get_structure( caps, 0 ); + gst_structure_get_int(structure, "width", &(stream.width)); + gst_structure_get_int(structure, "height", &(stream.height)); + string_format = gst_structure_get_string(structure, "format"); + if(string_format) { + fourcc = _mmplayer_convert_fourcc_string_to_value(string_format); + } + stream.format = util_get_pixtype(fourcc); + gst_caps_unref( caps ); + caps = NULL; + + /* + debug_log( "Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]", + GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format ); + */ + + if (stream.width == 0 || stream.height == 0 || stream.format == MM_PIXEL_FORMAT_INVALID) { + debug_error("Wrong condition!!"); + return TRUE; + } + + /* set size and timestamp */ + dataBlock = gst_buffer_peek_memory(buffer, 0); + stream.length_total = gst_memory_get_sizes(dataBlock, NULL, NULL); + stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */ + + /* check zero-copy */ + if (player->set_mode.video_zc && + player->set_mode.media_packet_video_stream && + gst_buffer_n_memory(buffer) > 1) { + metaBlock = gst_buffer_peek_memory(buffer, 1); + gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ); + video_buffer = (MMVideoBuffer *)mapinfo.data; + } + + if (video_buffer) { + /* set tbm bo */ + if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) { + /* copy pointer of tbm bo, stride, elevation */ + memcpy(stream.bo, video_buffer->handle.bo, + sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX); + } + else if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_PHYSICAL_ADDRESS) { + memcpy(stream.data, video_buffer->data, + sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX); + } + memcpy(stream.stride, video_buffer->stride_width, + sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX); + memcpy(stream.elevation, video_buffer->stride_height, + sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX); + /* set gst buffer */ + stream.internal_buffer = buffer; + } else { + tbm_bo_handle thandle; + int stride = ((stream.width + 3) & (~3)); + int elevation = stream.height; + int size = stride * elevation * 3 / 2; + gboolean gst_ret; + gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE); + if(!gst_ret) { + debug_error("fail to gst_memory_map"); + return GST_PAD_PROBE_OK; + } + + stream.stride[0] = stride; + stream.elevation[0] = elevation; + if(stream.format == MM_PIXEL_FORMAT_I420) { + stream.stride[1] = stream.stride[2] = stride / 2; + stream.elevation[1] = stream.elevation[2] = elevation / 2; + } + else { + debug_error("default #plane is 2, format %d", stream.format); + stream.stride[1] = stride; + stream.elevation[1] = elevation / 2; + } + + stream.bo[0] = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT); + if(!stream.bo[0]) { + debug_error("Fail to tbm_bo_alloc!!"); + return TRUE; + } + thandle = tbm_bo_map(stream.bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE); + if(thandle.ptr && mapinfo.data) + memcpy(thandle.ptr, mapinfo.data, size); + else + debug_error("data pointer is wrong. dest : %p, src : %p", + thandle.ptr, mapinfo.data); + + tbm_bo_unmap(stream.bo[0]); + } + + if (player->video_stream_cb) { + player->video_stream_cb(&stream, player->video_stream_cb_user_param); + } + + if (metaBlock) { + gst_memory_unmap(metaBlock, &mapinfo); + }else { + gst_memory_unmap(dataBlock, &mapinfo); + tbm_bo_unref(stream.bo[0]); + } + + return GST_PAD_PROBE_OK; +} + +static int +__mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket, gboolean use_video_stream) +{ + gchar* video_csc = "videoconvert"; // default colorspace converter + GList* element_bucket = *bucket; + + return_val_if_fail(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_FENTER(); + + if (!player->set_mode.media_packet_video_stream && use_video_stream) + { + if (player->set_mode.video_zc && strlen(player->ini.name_of_video_converter) > 0) + { + video_csc = player->ini.name_of_video_converter; + } + + MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player); + debug_log("using video converter: %s", video_csc); + + if ( !player->set_mode.video_zc) + { + gint width = 0; //width of video + gint height = 0; //height of video + GstCaps* video_caps = NULL; + GstStructure *structure = NULL; + + /* rotator, scaler and capsfilter */ + MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player); + MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_SCALE, "videoscale", "video scaler", TRUE, player); + MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CAPS, "capsfilter", "videocapsfilter", TRUE, player); + + /* get video stream caps parsed by demuxer */ + + mm_attrs_get_int_by_name(player->attrs, "display_width", &width); + + if(width) + structure = gst_structure_new("video/x-raw", "width", G_TYPE_INT, width, NULL); + + mm_attrs_get_int_by_name(player->attrs, "display_height", &height); + + if(structure && height) { + gst_structure_set (structure, "height", G_TYPE_INT, height, NULL); + + video_caps = gst_caps_new_full(structure, NULL); + g_object_set (GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_CAPS].gst), "caps", video_caps, NULL ); + MMPLAYER_LOG_GST_CAPS_TYPE(video_caps); + gst_caps_unref(video_caps); + } + else + debug_error("fail to set capsfilter %p, width %d, height %d", structure, width, height); + + if(structure) + gst_structure_free(structure); + + } + } + else + { + MMDisplaySurfaceType surface_type = MM_DISPLAY_SURFACE_NULL; + mm_attrs_get_int_by_name (player->attrs, "display_surface_type", (int *)&surface_type); + + if (player->set_mode.video_zc) + { + if ( (surface_type == MM_DISPLAY_SURFACE_EVAS) && ( !strcmp(player->ini.videosink_element_evas, "evasimagesink")) ) + { + video_csc = player->ini.name_of_video_converter; + } + else + { + video_csc = ""; + } + } + + if (video_csc && (strcmp(video_csc, ""))) + { + MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player); + debug_log("using video converter: %s", video_csc); + } + + /* set video rotator */ + if ( !player->set_mode.video_zc ) + MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player); + + /* videoscaler */ + #if !defined(__arm__) + MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_SCALE, "videoscale", "videoscaler", TRUE, player); + #endif + } + + *bucket = element_bucket; + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; + +ERROR: + *bucket = NULL; + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_INTERNAL; +} + +/** + * This function is to create video pipeline. + * + * @param player [in] handle of player + * caps [in] src caps of decoder + * surface_type [in] surface type for video rendering + * + * @return This function returns zero on success. + * @remark + * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline + */ +/** + * VIDEO PIPELINE + * - x surface (arm/x86) : xvimagesink + * - evas surface (arm) : evaspixmapsink + * fimcconvert ! evasimagesink + * - evas surface (x86) : videoconvertor ! videoflip ! evasimagesink + */ +static int +__mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type) +{ + GstPad *pad = NULL; + MMHandleType attrs; + GList*element_bucket = NULL; + MMPlayerGstElement* first_element = NULL; + MMPlayerGstElement* videobin = NULL; + gchar *videosink_element = NULL; + + MMPLAYER_FENTER(); + + return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); + + /* alloc handles */ + videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM); + if ( !videobin ) + { + return MM_ERROR_PLAYER_NO_FREE_SPACE; + } + + player->pipeline->videobin = videobin; + + attrs = MMPLAYER_GET_ATTRS(player); + if ( !attrs ) + { + debug_error("cannot get content attribute"); + return MM_ERROR_PLAYER_INTERNAL; + } + + /* create bin */ + videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN; + videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin"); + if ( !videobin[MMPLAYER_V_BIN].gst ) + { + debug_error("failed to create videobin"); + goto ERROR; + } + + if( player->use_video_stream ) // video stream callback, so send raw video data to application + { + debug_log("using memsink\n"); + + if ( __mmplayer_gst_create_video_filters(player, &element_bucket, TRUE) != MM_ERROR_NONE) + goto ERROR; + + /* finally, create video sink. output will be BGRA8888. */ + MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, "avsysmemsink", "videosink", TRUE, player); + + MMPLAYER_SIGNAL_CONNECT( player, + videobin[MMPLAYER_V_SINK].gst, + MM_PLAYER_SIGNAL_TYPE_VIDEOBIN, + "video-stream", + G_CALLBACK(__mmplayer_videostream_cb), + player ); + } + else // render video data using sink plugin like xvimagesink + { + if ( __mmplayer_gst_create_video_filters(player, &element_bucket, FALSE) != MM_ERROR_NONE) + goto ERROR; + + /* set video sink */ + switch (surface_type) + { + case MM_DISPLAY_SURFACE_X: + if (strlen(player->ini.videosink_element_x) > 0) + videosink_element = player->ini.videosink_element_x; + else + goto ERROR; + break; + case MM_DISPLAY_SURFACE_EVAS: + if (strlen(player->ini.videosink_element_evas) > 0) + videosink_element = player->ini.videosink_element_evas; + else + goto ERROR; + break; + case MM_DISPLAY_SURFACE_X_EXT: + { + void *pixmap_id_cb = NULL; + mm_attrs_get_data_by_name(attrs, "display_overlay", &pixmap_id_cb); + if (pixmap_id_cb) /* this is used for the videoTextue(canvasTexture) overlay */ + { + videosink_element = player->ini.videosink_element_x; + } + else + { + debug_error("something wrong.. callback function for getting pixmap id is null"); + goto ERROR; + } + break; + } + case MM_DISPLAY_SURFACE_NULL: + if (strlen(player->ini.videosink_element_fake) > 0) + videosink_element = player->ini.videosink_element_fake; + else + goto ERROR; + break; + case MM_DISPLAY_SURFACE_REMOTE: + if (strlen(player->ini.videosink_element_remote) > 0) + videosink_element = player->ini.videosink_element_remote; + else + goto ERROR; + break; + default: + debug_error("unidentified surface type"); + goto ERROR; + } + + MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE, player); + debug_log("selected videosink name: %s", videosink_element); + + /* additional setting for sink plug-in */ + switch (surface_type) { + case MM_DISPLAY_SURFACE_X_EXT: + MMPLAYER_SIGNAL_CONNECT( player, + player->pipeline->videobin[MMPLAYER_V_SINK].gst, + MM_PLAYER_SIGNAL_TYPE_VIDEOBIN, + "frame-render-error", + G_CALLBACK(__mmplayer_videoframe_render_error_cb), + player ); + debug_log("videoTexture usage, connect a signal handler for pixmap rendering error"); + break; + case MM_DISPLAY_SURFACE_REMOTE: + { + char *stream_path = NULL; + int attr_ret = mm_attrs_get_string_by_name ( + attrs, "shm_stream_path", &stream_path ); + if(attr_ret == MM_ERROR_NONE && stream_path) { + g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), + "socket-path", stream_path, + "wait-for-connection", FALSE, + "sync", TRUE, + NULL); + debug_log("set path \"%s\" for shmsink", stream_path); + } else { + debug_error("Not set attribute of shm_stream_path"); + goto ERROR; + } + break; + } + default: + break; + } + } + + if (_mmplayer_update_video_param(player) != MM_ERROR_NONE) + goto ERROR; + + if (videobin[MMPLAYER_V_SINK].gst) + { + GstPad *sink_pad = NULL; + sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink"); + if (sink_pad) + { + MMPLAYER_SIGNAL_CONNECT (player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN, + "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player); + gst_object_unref (GST_OBJECT(sink_pad)); + } + else + { + debug_warning("failed to get sink pad from videosink\n"); + } + } + + /* store it as it's sink element */ + __mmplayer_add_sink( player, videobin[MMPLAYER_V_SINK].gst ); + + /* adding created elements to bin */ + if( ! __mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket) ) + { + debug_error("failed to add elements\n"); + goto ERROR; + } + + /* Linking elements in the bucket by added order */ + if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 ) + { + debug_error("failed to link elements\n"); + goto ERROR; + } + + /* get first element's sinkpad for creating ghostpad */ + first_element = (MMPlayerGstElement *)element_bucket->data; + if ( !first_element ) + { + debug_error("failed to get first element from bucket\n"); + goto ERROR; + } + + pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink"); + if ( !pad ) + { + debug_error("failed to get pad from first element\n"); + goto ERROR; + } + + /* create ghostpad */ + player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad); + if ( FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin) ) + { + debug_error("failed to add ghostpad to videobin\n"); + goto ERROR; + } + gst_object_unref(pad); + + /* done. free allocated variables */ + g_list_free(element_bucket); + + mm_attrs_set_int_by_name(attrs, "content_video_found", TRUE); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; + +ERROR: + debug_error("ERROR : releasing videobin\n"); + + g_list_free( element_bucket ); + + if (pad) + gst_object_unref(GST_OBJECT(pad)); + + /* release videobin with it's childs */ + if ( videobin[MMPLAYER_V_BIN].gst ) + { + gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst)); + } + + + MMPLAYER_FREEIF( videobin ); + + player->pipeline->videobin = NULL; + + return MM_ERROR_PLAYER_INTERNAL; +} + +static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player) +{ + GList *element_bucket = NULL; + MMPlayerGstElement *textbin = player->pipeline->textbin; + + MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player); + MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player); + g_object_set (G_OBJECT (textbin[MMPLAYER_T_IDENTITY].gst), + "signal-handoffs", FALSE, + NULL); + + MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player); + MMPLAYER_SIGNAL_CONNECT( player, + G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), + MM_PLAYER_SIGNAL_TYPE_TEXTBIN, + "handoff", + G_CALLBACK(__mmplayer_update_subtitle), + (gpointer)player ); + + g_object_set (G_OBJECT (textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL); + g_object_set (G_OBJECT (textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL); + g_object_set (G_OBJECT (textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL); + + if (!player->play_subtitle) + { + debug_log ("add textbin sink as sink element of whole pipeline.\n"); + __mmplayer_add_sink (player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst)); + } + + /* adding created elements to bin */ + debug_log("adding created elements to bin\n"); + if( !__mmplayer_gst_element_add_bucket_to_bin( GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket )) + { + debug_error("failed to add elements\n"); + goto ERROR; + } + + /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */ + GST_OBJECT_FLAG_UNSET (textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK); + GST_OBJECT_FLAG_UNSET (textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK); + + /* linking elements in the bucket by added order. */ + debug_log("Linking elements in the bucket by added order.\n"); + if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 ) + { + debug_error("failed to link elements\n"); + goto ERROR; + } + + /* done. free allocated variables */ + g_list_free(element_bucket); + + if (textbin[MMPLAYER_T_QUEUE].gst) + { + GstPad *pad = NULL; + GstPad *ghostpad = NULL; + + pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink"); + if (!pad) + { + debug_error("failed to get video pad of textbin\n"); + return MM_ERROR_PLAYER_INTERNAL; + } + + ghostpad = gst_ghost_pad_new("text_sink", pad); + gst_object_unref(pad); + + if (!ghostpad) + { + debug_error("failed to create ghostpad of textbin\n"); + goto ERROR; + } + + if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) + { + debug_error("failed to add ghostpad to textbin\n"); + goto ERROR; + } + } + + return MM_ERROR_NONE; + +ERROR: + g_list_free(element_bucket); + + return MM_ERROR_PLAYER_INTERNAL; +} + +static int __mmplayer_gst_create_text_pipeline(mm_player_t* player) +{ + MMPlayerGstElement *textbin = NULL; + GList *element_bucket = NULL; + gint i = 0; + + MMPLAYER_FENTER(); + + return_val_if_fail( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + /* alloc handles */ + textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM); + if ( ! textbin ) + { + debug_error("failed to allocate memory for textbin\n"); + return MM_ERROR_PLAYER_NO_FREE_SPACE; + } + + /* create bin */ + textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN; + textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin"); + if ( !textbin[MMPLAYER_T_BIN].gst ) + { + debug_error("failed to create textbin\n"); + goto ERROR; + } + + /* take it */ + player->pipeline->textbin = textbin; + + /* fakesink */ + if (player->use_textoverlay) + { + debug_log ("use textoverlay for displaying \n"); + + MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_QUEUE, "queue", "text_t_queue", textbin[MMPLAYER_T_BIN].gst, player); + + MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_QUEUE, "queue", "text_v_queue", textbin[MMPLAYER_T_BIN].gst, player); + + MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_CONVERTER, "fimcconvert", "text_v_converter", textbin[MMPLAYER_T_BIN].gst, player); + + MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_OVERLAY, "textoverlay", "text_overlay", textbin[MMPLAYER_T_BIN].gst, player); + + if (!gst_element_link_pads (textbin[MMPLAYER_T_VIDEO_QUEUE].gst, "src", textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "sink")) + { + debug_error("failed to link queue and converter\n"); + goto ERROR; + } + + if (!gst_element_link_pads (textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "video_sink")) + { + debug_error("failed to link queue and textoverlay\n"); + goto ERROR; + } + + if (!gst_element_link_pads (textbin[MMPLAYER_T_QUEUE].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "text_sink")) + { + debug_error("failed to link queue and textoverlay\n"); + goto ERROR; + } + } + else + { + int surface_type = 0; + + debug_log ("use subtitle message for displaying \n"); + + mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type); + + switch(surface_type) + { + case MM_DISPLAY_SURFACE_X: + case MM_DISPLAY_SURFACE_EVAS: + case MM_DISPLAY_SURFACE_GL: + case MM_DISPLAY_SURFACE_NULL: + case MM_DISPLAY_SURFACE_X_EXT: + case MM_DISPLAY_SURFACE_REMOTE: + if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) + { + debug_error("failed to make plain text elements\n"); + goto ERROR; + } + break; + + default: + break; + } + } + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; + +ERROR: + + debug_log("ERROR : releasing textbin\n"); + + g_list_free( element_bucket ); + + /* release element which are not added to bin */ + for ( i = 1; i < MMPLAYER_T_NUM; i++ ) /* NOTE : skip bin */ + { + if ( textbin[i].gst ) + { + GstObject* parent = NULL; + parent = gst_element_get_parent( textbin[i].gst ); + + if ( !parent ) + { + gst_object_unref(GST_OBJECT(textbin[i].gst)); + textbin[i].gst = NULL; + } + else + { + gst_object_unref(GST_OBJECT(parent)); + } + } + } + + /* release textbin with it's childs */ + if ( textbin[MMPLAYER_T_BIN].gst ) + { + gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst)); + } + + MMPLAYER_FREEIF( textbin ); + + player->pipeline->textbin = NULL; + + return MM_ERROR_PLAYER_INTERNAL; +} + + +static int +__mmplayer_gst_create_subtitle_src(mm_player_t* player) +{ + MMPlayerGstElement* mainbin = NULL; + MMHandleType attrs = 0; + GstElement *subsrc = NULL; + GstElement *subparse = NULL; + gchar *subtitle_uri =NULL; + const gchar *charset = NULL; + GstPad *pad = NULL; + + MMPLAYER_FENTER(); + + /* get mainbin */ + return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); + + mainbin = player->pipeline->mainbin; + + attrs = MMPLAYER_GET_ATTRS(player); + if ( !attrs ) + { + debug_error("cannot get content attribute\n"); + return MM_ERROR_PLAYER_INTERNAL; + } + + mm_attrs_get_string_by_name ( attrs, "subtitle_uri", &subtitle_uri ); + if ( !subtitle_uri || strlen(subtitle_uri) < 1) + { + debug_error("subtitle uri is not proper filepath.\n"); + return MM_ERROR_PLAYER_INVALID_URI; + } + debug_log("subtitle file path is [%s].\n", subtitle_uri); + + + /* create the subtitle source */ + subsrc = gst_element_factory_make("filesrc", "subtitle_source"); + if ( !subsrc ) + { + debug_error ( "failed to create filesrc element\n" ); + goto ERROR; + } + g_object_set(G_OBJECT (subsrc), "location", subtitle_uri, NULL); + + mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC; + mainbin[MMPLAYER_M_SUBSRC].gst = subsrc; + + if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) + { + debug_warning("failed to add queue\n"); + goto ERROR; + } + + /* subparse */ + subparse = gst_element_factory_make("subparse", "subtitle_parser"); + if ( !subparse ) + { + debug_error ( "failed to create subparse element\n" ); + goto ERROR; + } + + charset = util_get_charset(subtitle_uri); + if (charset) + { + debug_log ("detected charset is %s\n", charset ); + g_object_set (G_OBJECT (subparse), "subtitle-encoding", charset, NULL); + } + + mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE; + mainbin[MMPLAYER_M_SUBPARSE].gst = subparse; + + if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) + { + debug_warning("failed to add subparse\n"); + goto ERROR; + } + + if (!gst_element_link_pads (subsrc, "src", subparse, "sink")) + { + debug_warning("failed to link subsrc and subparse\n"); + goto ERROR; + } + + player->play_subtitle = TRUE; + player->adjust_subtitle_pos = 0; + + debug_log ("play subtitle using subtitle file\n"); + + if (player->pipeline->textbin == NULL) + { + if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) + { + debug_error("failed to create textbin. continuing without text\n"); + goto ERROR; + } + + if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst))) + { + debug_warning("failed to add textbin\n"); + goto ERROR; + } + + debug_log ("link text input selector and textbin ghost pad"); + + player->textsink_linked = 1; + player->external_text_idx = 0; + debug_msg("player->textsink_linked set to 1\n"); + } + else + { + debug_log("text bin has been created. reuse it."); + player->external_text_idx = 1; + } + + if (!gst_element_link_pads (subparse, "src", player->pipeline->textbin[MMPLAYER_T_BIN].gst, "text_sink")) + { + debug_warning("failed to link subparse and textbin\n"); + goto ERROR; + } + + pad = gst_element_get_static_pad (player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst, "sink"); + + if (!pad) + { + debug_error("failed to get sink pad from textsink to probe data"); + return MM_ERROR_PLAYER_INTERNAL; + } + + gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, + __mmplayer_subtitle_adjust_position_probe, player, NULL); + + gst_object_unref(pad); + pad=NULL; + + /* create dot. for debugging */ + MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-with-subtitle" ); + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; + +ERROR: + player->textsink_linked = 0; + return MM_ERROR_PLAYER_INTERNAL; +} + +gboolean +__mmplayer_update_subtitle( GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data) +{ + mm_player_t* player = (mm_player_t*) data; + MMMessageParamType msg = {0, }; + GstClockTime duration = 0; + gpointer text = NULL; + guint text_size = 0; + gboolean ret = TRUE; + GstMapInfo mapinfo = GST_MAP_INFO_INIT; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, FALSE ); + return_val_if_fail ( buffer, FALSE ); + + gst_buffer_map(buffer, &mapinfo, GST_MAP_READ); + text = g_memdup(mapinfo.data, mapinfo.size); + text_size = mapinfo.size; + duration = GST_BUFFER_DURATION(buffer); + + + if ( player->set_mode.subtitle_off ) + { + debug_log("subtitle is OFF.\n" ); + return TRUE; + } + + if ( !text || (text_size == 0)) + { + debug_log("There is no subtitle to be displayed.\n" ); + return TRUE; + } + + msg.data = (void *) text; + msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration); + + debug_log("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data ); + + MMPLAYER_POST_MSG( player, MM_MESSAGE_UPDATE_SUBTITLE, &msg ); + gst_buffer_unmap(buffer, &mapinfo); + + MMPLAYER_FLEAVE(); + + return ret; +} + +static GstPadProbeReturn +__mmplayer_subtitle_adjust_position_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data) + +{ + mm_player_t *player = (mm_player_t *) u_data; + GstClockTime cur_timestamp = 0; + gint64 adjusted_timestamp = 0; + GstBuffer *buffer = gst_pad_probe_info_get_buffer(info); + + return_val_if_fail ( player, FALSE ); + + if ( player->set_mode.subtitle_off ) + { + debug_log("subtitle is OFF.\n" ); + return TRUE; + } + + if (player->adjust_subtitle_pos == 0 ) + { + debug_log("nothing to do"); + return TRUE; + } + + cur_timestamp = GST_BUFFER_TIMESTAMP(buffer); + adjusted_timestamp = (gint64) cur_timestamp + ((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000)); + + if ( adjusted_timestamp < 0) + { + debug_log("adjusted_timestamp under zero"); + MMPLAYER_FLEAVE(); + return FALSE; + } + + GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp; + debug_log("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "", + GST_TIME_ARGS(cur_timestamp), + GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer))); + + return GST_PAD_PROBE_OK; +} +static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position) +{ + MMPLAYER_FENTER(); + + /* check player and subtitlebin are created */ + return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED ); + return_val_if_fail ( player->play_subtitle, MM_ERROR_NOT_SUPPORT_API ); + + if (position == 0) + { + debug_log ("nothing to do\n"); + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; + } + + switch (format) + { + case MM_PLAYER_POS_FORMAT_TIME: + { + /* check current postion */ + player->adjust_subtitle_pos = position; + + debug_log("save adjust_subtitle_pos in player") ; + } + break; + + default: + { + debug_warning("invalid format.\n"); + MMPLAYER_FLEAVE(); + return MM_ERROR_INVALID_ARGUMENT; + } + } + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} +static int __gst_adjust_video_position(mm_player_t* player, int offset) +{ + MMPLAYER_FENTER(); + debug_log("adjusting video_pos in player") ; + int current_pos = 0; + /* check player and videobin are created */ + return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED ); + if ( !player->pipeline->videobin || + !player->pipeline->videobin[MMPLAYER_V_SINK].gst ) + { + debug_log("no video pipeline or sink is there"); + return MM_ERROR_PLAYER_INVALID_STATE ; + } + if (offset == 0) + { + debug_log ("nothing to do\n"); + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; + } + if(__gst_get_position ( player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)¤t_pos ) != MM_ERROR_NONE ) + { + debug_log("failed to get current position"); + return MM_ERROR_PLAYER_INTERNAL; + } + if ( (current_pos - offset ) < GST_TIME_AS_MSECONDS(player->duration) ) + { + debug_log("enter video delay is valid"); + } + else { + debug_log("enter video delay is crossing content boundary"); + return MM_ERROR_INVALID_ARGUMENT ; + } + g_object_set (G_OBJECT (player->pipeline->videobin[MMPLAYER_V_SINK].gst),"ts-offset",((gint64) offset * G_GINT64_CONSTANT(1000000)),NULL); + debug_log("video delay has been done"); + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +static void +__gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data) // @ +{ + GstElement *appsrc = element; + tBuffer *buf = (tBuffer *)user_data; + GstBuffer *buffer = NULL; + GstFlowReturn ret = GST_FLOW_OK; + gint len = size; + + return_if_fail ( element ); + return_if_fail ( buf ); + + buffer = gst_buffer_new (); + + if (buf->offset >= buf->len) + { + debug_log("call eos appsrc\n"); + g_signal_emit_by_name (appsrc, "end-of-stream", &ret); + return; + } + + if ( buf->len - buf->offset < size) + { + len = buf->len - buf->offset + buf->offset; + } + + gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, (guint8*)(buf->buf + buf->offset), g_free)); + GST_BUFFER_OFFSET(buffer) = buf->offset; + GST_BUFFER_OFFSET_END(buffer) = buf->offset + len; + + //debug_log("feed buffer %p, offset %u-%u length %u\n", buffer, buf->offset, buf->len,len); + g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret); + + buf->offset += len; +} + +static gboolean +__gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data) // @ +{ + tBuffer *buf = (tBuffer *)user_data; + + return_val_if_fail ( buf, FALSE ); + + buf->offset = (int)size; + + return TRUE; +} + +static void +__gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data) // @ +{ + mm_player_t *player = (mm_player_t*)user_data; + MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT; + + return_if_fail ( player ); + + debug_msg("app-src: feed data\n"); + + if (player->media_stream_buffer_status_cb[type]) + player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, player->buffer_cb_user_param); +} + +static gboolean +__gst_appsrc_seek_data(GstElement *element, guint64 offset, gpointer user_data) // @ +{ + mm_player_t *player = (mm_player_t*)user_data; + MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT; + + return_val_if_fail ( player, FALSE ); + + debug_msg("app-src: seek data\n"); + + if(player->media_stream_seek_data_cb[type]) + player->media_stream_seek_data_cb[type](type, offset, player->buffer_cb_user_param); + + return TRUE; +} + + +static gboolean +__gst_appsrc_enough_data(GstElement *element, gpointer user_data) // @ +{ + mm_player_t *player = (mm_player_t*)user_data; + MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT; + + return_val_if_fail ( player, FALSE ); + + debug_msg("app-src: enough data:%p\n", player->media_stream_buffer_status_cb[type]); + + if (player->media_stream_buffer_status_cb[type]) + player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, player->buffer_cb_user_param); + + return TRUE; +} + +int +_mmplayer_push_buffer(MMHandleType hplayer, unsigned char *buf, int size) // @ +{ + mm_player_t* player = (mm_player_t*)hplayer; + GstBuffer *buffer = NULL; + GstFlowReturn gst_ret = GST_FLOW_OK; + int ret = MM_ERROR_NONE; +// gint len = size; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + /* check current state */ +// MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_START ); + + + /* NOTE : we should check and create pipeline again if not created as we destroy + * whole pipeline when stopping in streamming playback + */ + if ( ! player->pipeline ) + { + if ( MM_ERROR_NONE != __gst_realize( player ) ) + { + debug_error("failed to realize before starting. only in streamming\n"); + return MM_ERROR_PLAYER_INTERNAL; + } + } + + debug_msg("app-src: pushing data\n"); + + if ( buf == NULL ) + { + debug_error("buf is null\n"); + return MM_ERROR_NONE; + } + + buffer = gst_buffer_new (); + + if (size <= 0) + { + debug_log("call eos appsrc\n"); + g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "end-of-stream", &gst_ret); + return MM_ERROR_NONE; + } + + //gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, (guint8*)(buf->buf + buf->offset), g_free)); + + debug_log("feed buffer %p, length %u\n", buf, size); + g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "push-buffer", buffer, &gst_ret); + + MMPLAYER_FLEAVE(); + + return ret; +} + +static GstBusSyncReply +__mmplayer_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data) +{ + mm_player_t *player = (mm_player_t *)data; + GstBusSyncReply reply = GST_BUS_DROP; + + if ( ! ( player->pipeline && player->pipeline->mainbin ) ) + { + debug_error("player pipeline handle is null"); + return GST_BUS_PASS; + } + + if (!__mmplayer_check_useful_message(player, message)) + { + gst_message_unref (message); + return GST_BUS_DROP; + } + + switch (GST_MESSAGE_TYPE (message)) + { + case GST_MESSAGE_STATE_CHANGED: + /* post directly for fast launch */ + if (player->sync_handler) { + __mmplayer_gst_callback(NULL, message, player); + reply = GST_BUS_DROP; + } + else { + reply = GST_BUS_PASS; + } + break; + case GST_MESSAGE_TAG: + __mmplayer_gst_extract_tag_from_msg(player, message); + + #if 0 // debug + { + GstTagList *tags = NULL; + + gst_message_parse_tag (message, &tags); + if (tags) { + debug_error("TAGS received from element \"%s\".\n", + GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message)))); + + gst_tag_list_foreach (tags, print_tag, NULL); + gst_tag_list_free (tags); + tags = NULL; + } + break; + } + #endif + break; + + case GST_MESSAGE_DURATION_CHANGED: + __mmplayer_gst_handle_duration(player, message); + break; + case GST_MESSAGE_ASYNC_DONE: + /* NOTE:Don't call gst_callback directly + * because previous frame can be showed even though this message is received for seek. + */ + default: + reply = GST_BUS_PASS; + break; + } + + if (reply == GST_BUS_DROP) + gst_message_unref (message); + + return reply; +} + +static gboolean +__mmplayer_gst_create_decoder ( mm_player_t *player, + MMPlayerTrackType track, + GstPad* srcpad, + enum MainElementID elemId, + const gchar* name) +{ + gboolean ret = TRUE; + GstPad *sinkpad = NULL; + + MMPLAYER_FENTER(); + + return_val_if_fail( player && + player->pipeline && + player->pipeline->mainbin, FALSE); + return_val_if_fail((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE); + return_val_if_fail(srcpad, FALSE); + return_val_if_fail((player->pipeline->mainbin[elemId].gst == NULL), FALSE); + + GstElement *decodebin = NULL; + GstCaps *dec_caps = NULL; + + /* create decodebin */ + decodebin = gst_element_factory_make("decodebin", name); + + if (!decodebin) + { + debug_error("error : fail to create decodebin for %d decoder\n", track); + ret = FALSE; + goto ERROR; + } + + /* raw pad handling signal */ + MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", + G_CALLBACK(__mmplayer_gst_decode_pad_added), player); + + /* This signal is emitted whenever decodebin finds a new stream. It is emitted + before looking for any elements that can handle that stream.*/ + MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", + G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player); + + /* This signal is emitted when a element is added to the bin.*/ + MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added", + G_CALLBACK(__mmplayer_gst_element_added), player); + + if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) + { + debug_error("failed to add new decodebin\n"); + ret = FALSE; + goto ERROR; + } + + dec_caps = gst_pad_query_caps (srcpad, NULL); + if (dec_caps) + { + //debug_log ("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps); + g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL); + gst_caps_unref(dec_caps); + } + + player->pipeline->mainbin[elemId].id = elemId; + player->pipeline->mainbin[elemId].gst = decodebin; + + sinkpad = gst_element_get_static_pad (decodebin, "sink"); + + if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) + { + debug_warning ("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad)); + gst_object_unref (GST_OBJECT(decodebin)); + } + + if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent (decodebin)) + { + debug_error("failed to sync second level decodebin state with parent\n"); + } + + debug_log("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num); + +ERROR: + if (sinkpad) + { + gst_object_unref ( GST_OBJECT(sinkpad) ); + sinkpad = NULL; + } + MMPLAYER_FLEAVE(); + + return ret; +} + +/** + * This function is to create audio or video pipeline for playing. + * + * @param player [in] handle of player + * + * @return This function returns zero on success. + * @remark + * @see + */ +static int +__mmplayer_gst_create_pipeline(mm_player_t* player) // @ +{ + GstBus *bus = NULL; + MMPlayerGstElement *mainbin = NULL; + MMHandleType attrs = 0; + GstElement* element = NULL; + GstElement* elem_src_audio = NULL; + GstElement* elem_src_subtitle = NULL; + GstElement* es_video_queue = NULL; + GstElement* es_audio_queue = NULL; + GstElement* es_subtitle_queue = NULL; + GList* element_bucket = NULL; + gboolean need_state_holder = TRUE; + gint i = 0; + + MMPLAYER_FENTER(); + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + /* get profile attribute */ + attrs = MMPLAYER_GET_ATTRS(player); + if ( !attrs ) + { + debug_error("cannot get content attribute\n"); + goto INIT_ERROR; + } + + /* create pipeline handles */ + if ( player->pipeline ) + { + debug_warning("pipeline should be released before create new one\n"); + goto INIT_ERROR; + } + + player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0( sizeof(MMPlayerGstPipelineInfo) ); + if (player->pipeline == NULL) + goto INIT_ERROR; + + memset( player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo) ); + + + /* create mainbin */ + mainbin = (MMPlayerGstElement*) g_malloc0( sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM ); + if (mainbin == NULL) + goto INIT_ERROR; + + memset( mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); + + /* create pipeline */ + mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE; + mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player"); + if ( ! mainbin[MMPLAYER_M_PIPE].gst ) + { + debug_error("failed to create pipeline\n"); + goto INIT_ERROR; + } + player->demux_pad_index = 0; + player->subtitle_language_list = NULL; + + player->is_subtitle_force_drop = FALSE; + player->last_multiwin_status = FALSE; + + _mmplayer_track_initialize(player); + + /* create source element */ + switch ( player->profile.uri_type ) + { + /* rtsp streamming */ + case MM_PLAYER_URI_TYPE_URL_RTSP: + { + gint network_bandwidth; + gchar *user_agent, *wap_profile; + + element = gst_element_factory_make(player->ini.name_of_rtspsrc, "streaming_source"); + + if ( !element ) + { + debug_error("failed to create streaming source element\n"); + break; + } + + debug_log("using streamming source [%s].\n", player->ini.name_of_rtspsrc); + + /* make it zero */ + network_bandwidth = 0; + user_agent = wap_profile = NULL; + + /* get attribute */ + mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent ); + mm_attrs_get_string_by_name ( attrs,"streaming_wap_profile", &wap_profile ); + mm_attrs_get_int_by_name ( attrs, "streaming_network_bandwidth", &network_bandwidth ); + + secure_debug_log("user_agent : %s\n", user_agent); + secure_debug_log("wap_profile : %s\n", wap_profile); + + /* setting property to streaming source */ + g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL); + if ( user_agent ) + g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL); + if ( wap_profile ) + g_object_set(G_OBJECT(element), "wap_profile", wap_profile, NULL); + + MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", + G_CALLBACK (__mmplayer_gst_rtp_dynamic_pad), player ); + MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", + G_CALLBACK (__mmplayer_gst_rtp_no_more_pads), player ); + + player->use_decodebin = FALSE; + } + break; +#if 0 + /* WFD streamming */ + case MM_PLAYER_URI_TYPE_URL_WFD: + { + element = gst_element_factory_make("wfdrtspsrc", "wfd_source"); + if ( !element ) + { + debug_error("failed to create wfd streaming source element\n"); + break; + } + debug_log("using wfd streamming source wfdrtspsrc.\n"); + g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL); + g_object_set(G_OBJECT(element), "debug", TRUE, NULL); + g_object_set(G_OBJECT(element), "latency", 0, NULL); + MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", + G_CALLBACK (__mmplayer_gst_wfd_dynamic_pad), player ); + + player->use_decodebin = FALSE; + } + break; +#endif + /* http streaming*/ + case MM_PLAYER_URI_TYPE_URL_HTTP: + { + gchar *user_agent, *proxy, *cookies, **cookie_list; + gint http_timeout = DEFAULT_HTTP_TIMEOUT; + user_agent = proxy = cookies = NULL; + cookie_list = NULL; + gint mode = MM_PLAYER_PD_MODE_NONE; + + mm_attrs_get_int_by_name ( attrs, "pd_mode", &mode ); + + player->pd_mode = mode; + + debug_log("http playback, PD mode : %d\n", player->pd_mode); + + if ( ! MMPLAYER_IS_HTTP_PD(player) ) + { + element = gst_element_factory_make(player->ini.name_of_httpsrc, "http_streaming_source"); + if ( !element ) + { + debug_error("failed to create http streaming source element[%s].\n", player->ini.name_of_httpsrc); + break; + } + debug_log("using http streamming source [%s].\n", player->ini.name_of_httpsrc); + + /* get attribute */ + mm_attrs_get_string_by_name ( attrs, "streaming_cookie", &cookies ); + mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent ); + mm_attrs_get_string_by_name ( attrs, "streaming_proxy", &proxy ); + mm_attrs_get_int_by_name ( attrs, "streaming_timeout", &http_timeout ); + + if ((http_timeout == DEFAULT_HTTP_TIMEOUT) && + (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) + { + debug_log("get timeout from ini\n"); + http_timeout = player->ini.http_timeout; + } + + /* get attribute */ + secure_debug_log("location : %s\n", player->profile.uri); + secure_debug_log("cookies : %s\n", cookies); + secure_debug_log("proxy : %s\n", proxy); + secure_debug_log("user_agent : %s\n", user_agent); + debug_log("timeout : %d\n", http_timeout); + + /* setting property to streaming source */ + g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL); + g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL); + g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL); + + /* check if prosy is vailid or not */ + if ( util_check_valid_url ( proxy ) ) + g_object_set(G_OBJECT(element), "proxy", proxy, NULL); + /* parsing cookies */ + if ( ( cookie_list = util_get_cookie_list ((const char*)cookies) ) ) + g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL); + if ( user_agent ) + g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL); + + if ( MMPLAYER_URL_HAS_DASH_SUFFIX(player) ) + { + debug_warning("it's dash. and it's still experimental feature."); + } + } + else // progressive download + { + gchar* location = NULL; + + if (player->pd_mode == MM_PLAYER_PD_MODE_URI) + { + gchar *path = NULL; + + mm_attrs_get_string_by_name ( attrs, "pd_location", &path ); + + MMPLAYER_FREEIF(player->pd_file_save_path); + + debug_log("PD Location : %s\n", path); + + if ( path ) + { + player->pd_file_save_path = g_strdup(path); + } + else + { + debug_error("can't find pd location so, it should be set \n"); + return MM_ERROR_PLAYER_FILE_NOT_FOUND; + } + } + + element = gst_element_factory_make("pdpushsrc", "PD pushsrc"); + if ( !element ) + { + debug_error("failed to create PD push source element[%s].\n", "pdpushsrc"); + break; + } + + if (player->pd_mode == MM_PLAYER_PD_MODE_URI) + g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL); + else + g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL); + + g_object_get(element, "location", &location, NULL); + debug_log("PD_LOCATION [%s].\n", location); + if (location) + g_free (location); + } + } + break; + + /* file source */ + case MM_PLAYER_URI_TYPE_FILE: + { + + debug_log("using filesrc for 'file://' handler.\n"); + + element = gst_element_factory_make("filesrc", "source"); + + if ( !element ) + { + debug_error("failed to create filesrc\n"); + break; + } + + g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */ + //g_object_set(G_OBJECT(element), "use-mmap", TRUE, NULL); + } + break; + + case MM_PLAYER_URI_TYPE_SS: + { + gint http_timeout = DEFAULT_HTTP_TIMEOUT; + element = gst_element_factory_make("souphttpsrc", "http streaming source"); + if ( !element ) + { + debug_error("failed to create http streaming source element[%s]", player->ini.name_of_httpsrc); + break; + } + + mm_attrs_get_int_by_name ( attrs, "streaming_timeout", &http_timeout ); + + if ((http_timeout == DEFAULT_HTTP_TIMEOUT) && + (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) + { + debug_log("get timeout from ini\n"); + http_timeout = player->ini.http_timeout; + } + + /* setting property to streaming source */ + g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL); + g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL); + } + break; + + /* appsrc */ + case MM_PLAYER_URI_TYPE_BUFF: + { + guint64 stream_type = GST_APP_STREAM_TYPE_STREAM; + + debug_log("mem src is selected\n"); + + element = gst_element_factory_make("appsrc", "buff-source"); + if ( !element ) + { + debug_error("failed to create appsrc element\n"); + break; + } + + g_object_set( element, "stream-type", stream_type, NULL ); + //g_object_set( element, "size", player->mem_buf.len, NULL ); + //g_object_set( element, "blocksize", (guint64)20480, NULL ); + + MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", + G_CALLBACK(__gst_appsrc_seek_data), player); + MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", + G_CALLBACK(__gst_appsrc_feed_data), player); + MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data", + G_CALLBACK(__gst_appsrc_enough_data), player); + } + break; + case MM_PLAYER_URI_TYPE_ES_BUFF: + { + debug_log("es buff src is selected\n"); + + if (player->v_stream_caps) + { + element = gst_element_factory_make("appsrc", "video_appsrc"); + if ( !element ) + { + debug_critical("failed to create video app source element[appsrc].\n" ); + break; + } + + if ( player->a_stream_caps ) + { + elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc"); + if ( !elem_src_audio ) + { + debug_critical("failed to create audio app source element[appsrc].\n" ); + break; + } + } + } + else if ( player->a_stream_caps ) + { + /* no video, only audio pipeline*/ + element = gst_element_factory_make("appsrc", "audio_appsrc"); + if ( !element ) + { + debug_critical("failed to create audio app source element[appsrc].\n" ); + break; + } + } + + if ( player->s_stream_caps ) + { + elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc"); + if ( !elem_src_subtitle ) + { + debug_critical("failed to create subtitle app source element[appsrc].\n" ); + break; + } + } + + debug_log("setting app sources properties.\n"); + debug_log("location : %s\n", player->profile.uri); + + if ( player->v_stream_caps && element ) + { + g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME, + "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */ + "caps", player->v_stream_caps, NULL); + + if ( player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0) + g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL); + if ( player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0) + g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL); + + /*Fix Seek External Demuxer: set audio and video appsrc as seekable */ + gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE); + MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", + G_CALLBACK(__gst_seek_video_data), player); + + if (player->a_stream_caps && elem_src_audio) + { + g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME, + "caps", player->a_stream_caps, NULL); + + if ( player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0) + g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL); + if ( player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0) + g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL); + + /*Fix Seek External Demuxer: set audio and video appsrc as seekable */ + gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE); + MMPLAYER_SIGNAL_CONNECT( player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", + G_CALLBACK(__gst_seek_audio_data), player); + } + } + else if (player->a_stream_caps && element) + { + g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME, + "caps", player->a_stream_caps, NULL); + + if ( player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0) + g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL); + if ( player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0) + g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL); + + /*Fix Seek External Demuxer: set audio and video appsrc as seekable */ + gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE); + MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", + G_CALLBACK(__gst_seek_audio_data), player); + } + + if (player->s_stream_caps && elem_src_subtitle) + { + g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME, + "caps", player->s_stream_caps, NULL); + + if ( player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0) + g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL); + if ( player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0) + g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL); + + gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE); + + MMPLAYER_SIGNAL_CONNECT( player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", + G_CALLBACK(__gst_seek_subtitle_data), player); + } + + if (!player->es_player_push_mode) + { + if (player->v_stream_caps && element) + { + MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", + G_CALLBACK(__gst_appsrc_feed_video_data), player); + MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data", + G_CALLBACK(__gst_appsrc_enough_video_data), player); + + if (player->a_stream_caps && elem_src_audio) + { + MMPLAYER_SIGNAL_CONNECT( player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", + G_CALLBACK(__gst_appsrc_feed_audio_data), player); + MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data", + G_CALLBACK(__gst_appsrc_enough_audio_data), player); + } + } + else if (player->a_stream_caps && element) + { + MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", + G_CALLBACK(__gst_appsrc_feed_audio_data), player); + MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data", + G_CALLBACK(__gst_appsrc_enough_audio_data), player); + } + + if (player->s_stream_caps && elem_src_subtitle) + { + MMPLAYER_SIGNAL_CONNECT( player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", + G_CALLBACK(__gst_appsrc_feed_subtitle_data), player); + } + } + + need_state_holder = FALSE; + } + break; + /* appsrc */ + case MM_PLAYER_URI_TYPE_MEM: + { + guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS; + + debug_log("mem src is selected\n"); + + element = gst_element_factory_make("appsrc", "mem-source"); + if ( !element ) + { + debug_error("failed to create appsrc element\n"); + break; + } + + g_object_set( element, "stream-type", stream_type, NULL ); + g_object_set( element, "size", player->mem_buf.len, NULL ); + g_object_set( element, "blocksize", (guint64)20480, NULL ); + + MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", + G_CALLBACK(__gst_appsrc_seek_data_mem), &player->mem_buf ); + MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", + G_CALLBACK(__gst_appsrc_feed_data_mem), &player->mem_buf ); + } + break; + case MM_PLAYER_URI_TYPE_URL: + break; + + case MM_PLAYER_URI_TYPE_TEMP: + break; + + case MM_PLAYER_URI_TYPE_NONE: + default: + break; + } + + /* check source element is OK */ + if ( ! element ) + { + debug_error("no source element was created.\n"); + goto INIT_ERROR; + } + + /* take source element */ + mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC; + mainbin[MMPLAYER_M_SRC].gst = element; + element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]); + + if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) + { + player->streamer = __mm_player_streaming_create(); + __mm_player_streaming_initialize(player->streamer); + } + + if ( MMPLAYER_IS_HTTP_PD(player) ) + { + gdouble pre_buffering_time = (gdouble)player->streamer->buffering_req.initial_second; + + debug_log ("Picked queue2 element(pre buffer : %d sec)....\n", pre_buffering_time); + element = gst_element_factory_make("queue2", "queue2"); + if ( !element ) + { + debug_error ( "failed to create http streaming buffer element\n" ); + goto INIT_ERROR; + } + + /* take it */ + mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER; + mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element; + element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]); + + pre_buffering_time = (pre_buffering_time > 0)?(pre_buffering_time):(player->ini.http_buffering_time); + + __mm_player_streaming_set_queue2(player->streamer, + element, + TRUE, + player->ini.http_max_size_bytes, + pre_buffering_time, + 1.0, + player->ini.http_buffering_limit, + FALSE, + NULL, + 0); + } + if (MMPLAYER_IS_ES_BUFF_SRC(player)) + { + if (player->v_stream_caps) + { + es_video_queue = gst_element_factory_make("queue2", "video_queue"); + if (!es_video_queue) + { + debug_error ("create es_video_queue for es player failed\n"); + goto INIT_ERROR; + } + mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER; + mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue; + element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]); + + /* Adding audio appsrc to bucket */ + if (player->a_stream_caps && elem_src_audio) + { + mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC; + mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio; + element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]); + + es_audio_queue = gst_element_factory_make("queue2", "audio_queue"); + if (!es_audio_queue) + { + debug_error ("create es_audio_queue for es player failed\n"); + goto INIT_ERROR; + } + mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER; + mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue; + element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]); + } + } + /* Only audio stream, no video */ + else if (player->a_stream_caps) + { + es_audio_queue = gst_element_factory_make("queue2", "audio_queue"); + if (!es_audio_queue) + { + debug_error ("create es_audio_queue for es player failed\n"); + goto INIT_ERROR; + } + mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER; + mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue; + element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]); + } + + if (player->s_stream_caps && elem_src_subtitle) + { + mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC; + mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle; + element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]); + + es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue"); + if (!es_subtitle_queue) + { + debug_error ("create es_subtitle_queue for es player failed\n"); + goto INIT_ERROR; + } + mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER; + mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue; + element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]); + } + } + + /* create autoplugging element if src element is not a rtsp src */ + if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) && + (player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_WFD) && + (player->profile.uri_type != MM_PLAYER_URI_TYPE_ES_BUFF)) + { + element = NULL; + enum MainElementID elemId = MMPLAYER_M_NUM; + + if ((player->use_decodebin) && + ((MMPLAYER_IS_HTTP_PD(player)) || + (!MMPLAYER_IS_HTTP_STREAMING(player)))) + { + elemId = MMPLAYER_M_AUTOPLUG; + element = __mmplayer_create_decodebin(player); + need_state_holder = FALSE; + } + else + { + elemId = MMPLAYER_M_TYPEFIND; + element = gst_element_factory_make("typefind", "typefinder"); + MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", + G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player ); + } + + + /* check autoplug element is OK */ + if ( ! element ) + { + debug_error("can not create element (%d)\n", elemId); + goto INIT_ERROR; + } + + mainbin[elemId].id = elemId; + mainbin[elemId].gst = element; + + element_bucket = g_list_append(element_bucket, &mainbin[elemId]); + } + + /* add elements to pipeline */ + if( !__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) + { + debug_error("Failed to add elements to pipeline\n"); + goto INIT_ERROR; + } + + + /* linking elements in the bucket by added order. */ + if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 ) + { + debug_error("Failed to link some elements\n"); + goto INIT_ERROR; + } + + + /* create fakesink element for keeping the pipeline state PAUSED. if needed */ + if ( need_state_holder ) + { + /* create */ + mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK; + mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make ("fakesink", "state-holder"); + + if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) + { + debug_error ("fakesink element could not be created\n"); + goto INIT_ERROR; + } + GST_OBJECT_FLAG_UNSET (mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK); + + /* take ownership of fakesink. we are reusing it */ + gst_object_ref( mainbin[MMPLAYER_M_SRC_FAKESINK].gst ); + + /* add */ + if ( FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), + mainbin[MMPLAYER_M_SRC_FAKESINK].gst) ) + { + debug_error("failed to add fakesink to bin\n"); + goto INIT_ERROR; + } + } + + /* now we have completed mainbin. take it */ + player->pipeline->mainbin = mainbin; + + if (MMPLAYER_IS_ES_BUFF_SRC(player)) + { + GstPad *srcpad = NULL; + + if (mainbin[MMPLAYER_M_V_BUFFER].gst) + { + srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src"); + if (srcpad) + { + __mmplayer_gst_create_decoder ( player, + MM_PLAYER_TRACK_TYPE_VIDEO, + srcpad, + MMPLAYER_M_AUTOPLUG_V_DEC, + "video_decodebin"); + + gst_object_unref ( GST_OBJECT(srcpad) ); + srcpad = NULL; + } + } + + if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) + { + srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src"); + if (srcpad) + { + __mmplayer_gst_create_decoder ( player, + MM_PLAYER_TRACK_TYPE_AUDIO, + srcpad, + MMPLAYER_M_AUTOPLUG_A_DEC, + "audio_decodebin"); + + gst_object_unref ( GST_OBJECT(srcpad) ); + srcpad = NULL; + } // else error + } // else error + + if (mainbin[MMPLAYER_M_S_BUFFER].gst) + { + __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps); + } + } + + /* connect bus callback */ + bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst)); + if ( !bus ) + { + debug_error ("cannot get bus from pipeline.\n"); + goto INIT_ERROR; + } + + player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player); + + player->context.thread_default = g_main_context_get_thread_default(); + + if (NULL == player->context.thread_default) + { + player->context.thread_default = g_main_context_default(); + debug_log("thread-default context is the global default context"); + } + debug_warning("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher); + + /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */ + if ( __mmplayer_check_subtitle ( player ) ) + { + if ( MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player) ) + debug_error("fail to create subtitle src\n"); + } + + /* set sync handler to get tag synchronously */ + gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL); + + /* finished */ + gst_object_unref(GST_OBJECT(bus)); + g_list_free(element_bucket); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; + +INIT_ERROR: + + __mmplayer_gst_destroy_pipeline(player); + g_list_free(element_bucket); + + /* release element which are not added to bin */ + for ( i = 1; i < MMPLAYER_M_NUM; i++ ) /* NOTE : skip pipeline */ + { + if ( mainbin[i].gst ) + { + GstObject* parent = NULL; + parent = gst_element_get_parent( mainbin[i].gst ); + + if ( !parent ) + { + gst_object_unref(GST_OBJECT(mainbin[i].gst)); + mainbin[i].gst = NULL; + } + else + { + gst_object_unref(GST_OBJECT(parent)); + } + } + } + + /* release pipeline with it's childs */ + if ( mainbin[MMPLAYER_M_PIPE].gst ) + { + gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst)); + } + + MMPLAYER_FREEIF( player->pipeline ); + MMPLAYER_FREEIF( mainbin ); + + return MM_ERROR_PLAYER_INTERNAL; +} + +static void +__mmplayer_reset_gapless_state(mm_player_t* player) +{ + MMPLAYER_FENTER(); + return_if_fail(player + && player->pipeline + && player->pipeline->audiobin + && player->pipeline->audiobin[MMPLAYER_A_BIN].gst); + + if (player->gapless.audio_data_probe_id != 0) + { + GstPad *sinkpad; + sinkpad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_BIN].gst, "sink"); + gst_pad_remove_probe (sinkpad, player->gapless.audio_data_probe_id); + gst_object_unref (sinkpad); + } + memset(&player->gapless, 0, sizeof(mm_player_gapless_t)); + + MMPLAYER_FLEAVE(); + return; +} + +static int +__mmplayer_gst_destroy_pipeline(mm_player_t* player) // @ +{ + gint timeout = 0; + int ret = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_INVALID_HANDLE ); + + /* cleanup stuffs */ + MMPLAYER_FREEIF(player->type); + player->have_dynamic_pad = FALSE; + player->no_more_pad = FALSE; + player->num_dynamic_pad = 0; + player->demux_pad_index = 0; + player->subtitle_language_list = NULL; + player->use_deinterleave = FALSE; + player->max_audio_channels = 0; + player->video_share_api_delta = 0; + player->video_share_clock_delta = 0; + player->video_hub_download_mode = 0; + __mmplayer_reset_gapless_state(player); + __mmplayer_post_proc_reset(player); + + if (player->streamer) + { + __mm_player_streaming_deinitialize (player->streamer); + __mm_player_streaming_destroy(player->streamer); + player->streamer = NULL; + } + + /* cleanup unlinked mime type */ + MMPLAYER_FREEIF(player->unlinked_audio_mime); + MMPLAYER_FREEIF(player->unlinked_video_mime); + MMPLAYER_FREEIF(player->unlinked_demuxer_mime); + + /* cleanup running stuffs */ + __mmplayer_cancel_eos_timer( player ); +#if 0 //need to change and test + /* remove sound cb */ + if ( MM_ERROR_NONE != mm_sound_remove_device_information_changed_callback()) + { + debug_error("failed to mm_sound_remove_device_information_changed_callback()"); + } +#endif + /* cleanup gst stuffs */ + if ( player->pipeline ) + { + MMPlayerGstElement* mainbin = player->pipeline->mainbin; + GstTagList* tag_list = player->pipeline->tag_list; + + /* first we need to disconnect all signal hander */ + __mmplayer_release_signal_connection( player, MM_PLAYER_SIGNAL_TYPE_ALL ); + + /* disconnecting bus watch */ + if ( player->bus_watcher ) + __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher); + player->bus_watcher = 0; + + if ( mainbin ) + { + MMPlayerGstElement* audiobin = player->pipeline->audiobin; + MMPlayerGstElement* videobin = player->pipeline->videobin; + MMPlayerGstElement* textbin = player->pipeline->textbin; + GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (mainbin[MMPLAYER_M_PIPE].gst)); + gst_bus_set_sync_handler (bus, NULL, NULL, NULL); + gst_object_unref(bus); + + timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player); + ret = __mmplayer_gst_set_state ( player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout ); + if ( ret != MM_ERROR_NONE ) + { + debug_error("fail to change state to NULL\n"); + return MM_ERROR_PLAYER_INTERNAL; + } + + debug_warning("succeeded in chaning state to NULL\n"); + + gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst)); + + /* free fakesink */ + if ( mainbin[MMPLAYER_M_SRC_FAKESINK].gst ) + gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst)); + + /* free avsysaudiosink + avsysaudiosink should be unref when destory pipeline just after start play with BT. + Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed. + */ + MMPLAYER_FREEIF( audiobin ); + MMPLAYER_FREEIF( videobin ); + MMPLAYER_FREEIF( textbin ); + MMPLAYER_FREEIF( mainbin ); + } + + if ( tag_list ) + gst_tag_list_free(tag_list); + + MMPLAYER_FREEIF( player->pipeline ); + } + MMPLAYER_FREEIF(player->album_art); + + if (player->v_stream_caps) + { + gst_caps_unref(player->v_stream_caps); + player->v_stream_caps = NULL; + } + if (player->a_stream_caps) + { + gst_caps_unref(player->a_stream_caps); + player->a_stream_caps = NULL; + } + if (player->s_stream_caps) + { + gst_caps_unref(player->s_stream_caps); + player->s_stream_caps = NULL; + } + _mmplayer_track_destroy(player); + + if ( player->sink_elements ) + g_list_free ( player->sink_elements ); + player->sink_elements = NULL; + + debug_warning("finished destroy pipeline\n"); + + MMPLAYER_FLEAVE(); + + return ret; +} + +static int __gst_realize(mm_player_t* player) // @ +{ + gint timeout = 0; + int ret = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY; + + ret = __mmplayer_gst_create_pipeline(player); + if ( ret ) + { + debug_error("failed to create pipeline\n"); + return ret; + } + + /* set pipeline state to READY */ + /* NOTE : state change to READY must be performed sync. */ + timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player); + ret = __mmplayer_gst_set_state(player, + player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout); + + if ( ret != MM_ERROR_NONE ) + { + /* return error if failed to set state */ + debug_error("failed to set READY state"); + return ret; + } + else + { + MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_READY ); + } + + /* create dot before error-return. for debugging */ + MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-realize" ); + + MMPLAYER_FLEAVE(); + + return ret; +} + +static int __gst_unrealize(mm_player_t* player) // @ +{ + int ret = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL; + MMPLAYER_PRINT_STATE(player); + + /* release miscellaneous information */ + __mmplayer_release_misc( player ); + + /* destroy pipeline */ + ret = __mmplayer_gst_destroy_pipeline( player ); + if ( ret != MM_ERROR_NONE ) + { + debug_error("failed to destory pipeline\n"); + return ret; + } + + /* release miscellaneous information. + these info needs to be released after pipeline is destroyed. */ + __mmplayer_release_misc_post( player ); + + MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_NULL ); + + MMPLAYER_FLEAVE(); + + return ret; +} + +static int __gst_pending_seek ( mm_player_t* player ) +{ + MMPlayerStateType current_state = MM_PLAYER_STATE_NONE; + int ret = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + if ( !player->pending_seek.is_pending ) + { + debug_log("pending seek is not reserved. nothing to do.\n" ); + return ret; + } + + /* check player state if player could pending seek or not. */ + current_state = MMPLAYER_CURRENT_STATE(player); + + if ( current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING ) + { + debug_warning("try to pending seek in %s state, try next time. \n", + MMPLAYER_STATE_GET_NAME(current_state)); + return ret; + } + + debug_log("trying to play from (%lu) pending position\n", player->pending_seek.pos); + + ret = __gst_set_position ( player, player->pending_seek.format, player->pending_seek.pos, FALSE ); + + if ( MM_ERROR_NONE != ret ) + debug_error("failed to seek pending postion. just keep staying current position.\n"); + + player->pending_seek.is_pending = FALSE; + + MMPLAYER_FLEAVE(); + + return ret; +} + +static int __gst_start(mm_player_t* player) // @ +{ + gboolean sound_extraction = 0; + int ret = MM_ERROR_NONE; + gboolean async = FALSE; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + /* get sound_extraction property */ + mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction); + + /* NOTE : if SetPosition was called before Start. do it now */ + /* streaming doesn't support it. so it should be always sync */ + /* !! create one more api to check if there is pending seek rather than checking variables */ + if ( (player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) + { + MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED; + ret = __gst_pause(player, FALSE); + if ( ret != MM_ERROR_NONE ) + { + debug_error("failed to set state to PAUSED for pending seek\n"); + return ret; + } + + MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING; + + if ( sound_extraction ) + { + debug_log("setting pcm extraction\n"); + + ret = __mmplayer_set_pcm_extraction(player); + if ( MM_ERROR_NONE != ret ) + { + debug_warning("failed to set pcm extraction\n"); + return ret; + } + } + else + { + if ( MM_ERROR_NONE != __gst_pending_seek(player) ) + { + debug_warning("failed to seek pending postion. starting from the begin of content.\n"); + } + } + } + + debug_log("current state before doing transition"); + MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING; + MMPLAYER_PRINT_STATE(player); + + /* set pipeline state to PLAYING */ + if (player->es_player_push_mode) + { + async = TRUE; + } + /* set pipeline state to PLAYING */ + ret = __mmplayer_gst_set_state(player, + player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player) ); + + if (ret == MM_ERROR_NONE) + { + MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING); + } + else + { + debug_error("failed to set state to PLAYING"); + return ret; + } + + /* generating debug info before returning error */ + MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-start" ); + + MMPLAYER_FLEAVE(); + + return ret; +} + +static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time) +{ + MMPLAYER_FENTER(); + + return_if_fail(player + && player->pipeline + && player->pipeline->audiobin + && player->pipeline->audiobin[MMPLAYER_A_SINK].gst); + + g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 2, NULL); + + usleep(time); + + MMPLAYER_FLEAVE(); +} + +static void __mmplayer_undo_sound_fadedown(mm_player_t* player) +{ + MMPLAYER_FENTER(); + + return_if_fail(player + && player->pipeline + && player->pipeline->audiobin + && player->pipeline->audiobin[MMPLAYER_A_SINK].gst); + + g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL); + + MMPLAYER_FLEAVE(); +} + +static int __gst_stop(mm_player_t* player) // @ +{ + GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS; + MMHandleType attrs = 0; + gboolean fadedown = FALSE; + gboolean rewind = FALSE; + gint timeout = 0; + int ret = MM_ERROR_NONE; + GstState state; + gboolean async = FALSE; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail ( player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED); + + debug_log("current state before doing transition"); + MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY; + MMPLAYER_PRINT_STATE(player); + + attrs = MMPLAYER_GET_ATTRS(player); + if ( !attrs ) + { + debug_error("cannot get content attribute\n"); + return MM_ERROR_PLAYER_INTERNAL; + } + + mm_attrs_get_int_by_name(attrs, "sound_fadedown", &fadedown); + + /* enable fadedown */ + if (fadedown || player->sound_focus.by_asm_cb) + __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT); + + /* Just set state to PAUESED and the rewind. it's usual player behavior. */ + timeout = MMPLAYER_STATE_CHANGE_TIMEOUT ( player ); + + if (player->profile.uri_type == MM_PLAYER_URI_TYPE_BUFF || + player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS) + { + state = GST_STATE_READY; + } + else + { + state = GST_STATE_PAUSED; + + if ( ! MMPLAYER_IS_STREAMING(player) || + (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked)) { + rewind = TRUE; + } + } + + if (player->es_player_push_mode) + { + async = TRUE; + } + /* set gst state */ + ret = __mmplayer_gst_set_state( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, state, async, timeout ); + + /* disable fadeout */ + if (fadedown || player->sound_focus.by_asm_cb) + __mmplayer_undo_sound_fadedown(player); + + /* return if set_state has failed */ + if ( ret != MM_ERROR_NONE ) + { + debug_error("failed to set state.\n"); + return ret; + } + + /* rewind */ + if ( rewind ) + { + if ( ! __gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate, + GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0, + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE) ) + { + debug_warning("failed to rewind\n"); + ret = MM_ERROR_PLAYER_SEEK; + } + } + + /* initialize */ + player->sent_bos = FALSE; + + if (player->es_player_push_mode) //for cloudgame + { + timeout = 0; + } + + /* wait for seek to complete */ + change_ret = gst_element_get_state (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND); + if ( change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL ) + { + MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_READY ); + } + else + { + debug_error("fail to stop player.\n"); + ret = MM_ERROR_PLAYER_INTERNAL; + __mmplayer_dump_pipeline_state(player); + } + + /* generate dot file if enabled */ + MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-stop" ); + + MMPLAYER_FLEAVE(); + + return ret; +} + +int __gst_pause(mm_player_t* player, gboolean async) // @ +{ + int ret = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED); + + debug_log("current state before doing transition"); + MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED; + MMPLAYER_PRINT_STATE(player); + + /* set pipeline status to PAUSED */ + player->ignore_asyncdone = TRUE; + + ret = __mmplayer_gst_set_state(player, + player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player)); + + player->ignore_asyncdone = FALSE; + + if ( FALSE == async ) + { + if ( ret != MM_ERROR_NONE ) + { + GstMessage *msg = NULL; + GTimer *timer = NULL; + gdouble MAX_TIMEOUT_SEC = 3; + + debug_error("failed to set state to PAUSED"); + + timer = g_timer_new(); + g_timer_start(timer); + + GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)); + gboolean got_msg = FALSE; + /* check if gst error posted or not */ + do + { + msg = gst_bus_timed_pop(bus, GST_SECOND /2); + if (msg) + { + if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) + { + GError *error = NULL; + + /* parse error code */ + gst_message_parse_error(msg, &error, NULL); + + if ( gst_structure_has_name ( gst_message_get_structure(msg), "streaming_error" ) ) + { + /* Note : the streaming error from the streaming source is handled + * using __mmplayer_handle_streaming_error. + */ + __mmplayer_handle_streaming_error ( player, msg ); + + } + else if (error) + { + debug_error("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code); + + if (error->domain == GST_STREAM_ERROR) + { + ret = __gst_handle_stream_error( player, error, msg ); + } + else if (error->domain == GST_RESOURCE_ERROR) + { + ret = __gst_handle_resource_error( player, error->code ); + } + else if (error->domain == GST_LIBRARY_ERROR) + { + ret = __gst_handle_library_error( player, error->code ); + } + else if (error->domain == GST_CORE_ERROR) + { + ret = __gst_handle_core_error( player, error->code ); + } + } + + got_msg = TRUE; + player->msg_posted = TRUE; + } + gst_message_unref(msg); + } + } while (!got_msg && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC)); + /* clean */ + gst_object_unref(bus); + g_timer_stop (timer); + g_timer_destroy (timer); + + return ret; + } + else if ( (!player->pipeline->videobin) && (!player->pipeline->audiobin) ) + { + if (MMPLAYER_IS_RTSP_STREAMING(player)) + return ret; + return MM_ERROR_PLAYER_CODEC_NOT_FOUND; + } + else if ( ret== MM_ERROR_NONE) + { + MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PAUSED ); + } + } + + /* generate dot file before returning error */ + MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-pause" ); + + MMPLAYER_FLEAVE(); + + return ret; +} + +int __gst_resume(mm_player_t* player, gboolean async) // @ +{ + int ret = MM_ERROR_NONE; + gint timeout = 0; + + MMPLAYER_FENTER(); + + return_val_if_fail(player && player->pipeline, + MM_ERROR_PLAYER_NOT_INITIALIZED); + + debug_log("current state before doing transition"); + MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING; + MMPLAYER_PRINT_STATE(player); + + /* generate dot file before returning error */ + MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-resume" ); + + if ( async ) + debug_log("do async state transition to PLAYING.\n"); + + /* set pipeline state to PLAYING */ + timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player); + + ret = __mmplayer_gst_set_state(player, + player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout ); + if (ret != MM_ERROR_NONE) + { + debug_error("failed to set state to PLAYING\n"); + return ret; + } + else + { + if (async == FALSE) + { + // MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PLAYING ); + debug_log("update state machine to %d\n", MM_PLAYER_STATE_PLAYING); + ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING); + } + } + + /* generate dot file before returning error */ + MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-resume" ); + + MMPLAYER_FLEAVE(); + + return ret; +} + +static int +__gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called) // @ +{ + unsigned long dur_msec = 0; + gint64 dur_nsec = 0; + gint64 pos_nsec = 0; + gboolean ret = TRUE; + gboolean accurated = FALSE; + GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH; + + MMPLAYER_FENTER(); + return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED ); + return_val_if_fail ( !MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP ); + + if ( MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING + && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED ) + goto PENDING; + + if( !MMPLAYER_IS_ES_BUFF_SRC(player) ) + { + /* check duration */ + /* NOTE : duration cannot be zero except live streaming. + * Since some element could have some timing problemn with quering duration, try again. + */ + if ( !player->duration ) + { + if ( !gst_element_query_duration( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec )) + { + goto SEEK_ERROR; + } + player->duration = dur_nsec; + } + + if ( player->duration ) + { + dur_msec = GST_TIME_AS_MSECONDS(player->duration); + } + else + { + debug_error("could not get the duration. fail to seek.\n"); + goto SEEK_ERROR; + } + } + debug_log("playback rate: %f\n", player->playback_rate); + + mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated); + if (accurated) + { + seek_flags |= GST_SEEK_FLAG_ACCURATE; + } + else + { + seek_flags |= GST_SEEK_FLAG_KEY_UNIT; + } + + /* do seek */ + switch ( format ) + { + case MM_PLAYER_POS_FORMAT_TIME: + { + if( !MMPLAYER_IS_ES_BUFF_SRC(player) ) + { + /* check position is valid or not */ + if ( position > dur_msec ) + goto INVALID_ARGS; + + debug_log("seeking to (%lu) msec, duration is %d msec\n", position, dur_msec); + + if ( player->doing_seek ) + { + debug_log("not completed seek"); + return MM_ERROR_PLAYER_DOING_SEEK; + } + } + + if ( !internal_called ) + player->doing_seek = TRUE; + + pos_nsec = position * G_GINT64_CONSTANT(1000000); + + if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) + { + gint64 cur_time = 0; + + /* get current position */ + gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time); + + /* flush */ + GstEvent *event = gst_event_new_seek (1.0, + GST_FORMAT_TIME, + (GstSeekFlags)GST_SEEK_FLAG_FLUSH, + GST_SEEK_TYPE_SET, cur_time, + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); + if(event) { + __gst_send_event_to_sink(player, event); + } + + __gst_pause( player, FALSE ); + } + + ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate, + GST_FORMAT_TIME, seek_flags, + GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE ); + if ( !ret ) + { + debug_error("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec); + goto SEEK_ERROR; + } + } + break; + + case MM_PLAYER_POS_FORMAT_PERCENT: + { + debug_log("seeking to (%lu)%% \n", position); + + if (player->doing_seek) + { + debug_log("not completed seek"); + return MM_ERROR_PLAYER_DOING_SEEK; + } + + if ( !internal_called) + player->doing_seek = TRUE; + + /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */ + pos_nsec = (gint64) ( ( position * player->duration ) / 100 ); + ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate, + GST_FORMAT_TIME, seek_flags, + GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE ); + if ( !ret ) + { + debug_error("failed to set position. dur[%lud] pos[%lud] pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec); + goto SEEK_ERROR; + } + } + break; + + default: + goto INVALID_ARGS; + + } + + /* NOTE : store last seeking point to overcome some bad operation + * ( returning zero when getting current position ) of some elements + */ + player->last_position = pos_nsec; + + /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */ + if ( player->playback_rate > 1.0 ) + _mmplayer_set_playspeed ( (MMHandleType)player, player->playback_rate ); + + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; + +PENDING: + player->pending_seek.is_pending = TRUE; + player->pending_seek.format = format; + player->pending_seek.pos = position; + + debug_warning("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n", + MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos); + + return MM_ERROR_NONE; + +INVALID_ARGS: + debug_error("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format); + return MM_ERROR_INVALID_ARGUMENT; + +SEEK_ERROR: + player->doing_seek = FALSE; + return MM_ERROR_PLAYER_SEEK; +} + +#define TRICKPLAY_OFFSET GST_MSECOND + +static int +__gst_get_position(mm_player_t* player, int format, unsigned long* position) // @ +{ + MMPlayerStateType current_state = MM_PLAYER_STATE_NONE; + gint64 pos_msec = 0; + gboolean ret = TRUE; + + return_val_if_fail( player && position && player->pipeline && player->pipeline->mainbin, + MM_ERROR_PLAYER_NOT_INITIALIZED ); + + current_state = MMPLAYER_CURRENT_STATE(player); + + /* NOTE : query position except paused state to overcome some bad operation + * please refer to below comments in details + */ + if ( current_state != MM_PLAYER_STATE_PAUSED ) + { + ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec); + } + + /* NOTE : get last point to overcome some bad operation of some elements + * ( returning zero when getting current position in paused state + * and when failed to get postion during seeking + */ + if ( ( current_state == MM_PLAYER_STATE_PAUSED ) + || ( ! ret )) + //|| ( player->last_position != 0 && pos_msec == 0 ) ) + { + debug_log ("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS (pos_msec), ret, current_state); + + if(player->playback_rate < 0.0) + pos_msec = player->last_position - TRICKPLAY_OFFSET; + else + pos_msec = player->last_position; + + if (!ret) + pos_msec = player->last_position; + else + player->last_position = pos_msec; + + debug_log("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec)); + + } + else + { + if (player->duration > 0 && pos_msec > player->duration) { + pos_msec = player->duration; + } + + if (player->sound_focus.keep_last_pos) { + debug_log("return last pos as stop by asm, %"GST_TIME_FORMAT, GST_TIME_ARGS(player->last_position)); + pos_msec = player->last_position; + } + else { + player->last_position = pos_msec; + } + } + + switch (format) { + case MM_PLAYER_POS_FORMAT_TIME: + *position = GST_TIME_AS_MSECONDS(pos_msec); + break; + + case MM_PLAYER_POS_FORMAT_PERCENT: + { + gint64 dur = 0; + gint64 pos = 0; + + dur = player->duration / GST_SECOND; + if (dur <= 0) + { + debug_log ("duration is [%d], so returning position 0\n",dur); + *position = 0; + } + else + { + pos = pos_msec / GST_SECOND; + *position = pos * 100 / dur; + } + break; + } + default: + return MM_ERROR_PLAYER_INTERNAL; + } + + return MM_ERROR_NONE; +} + + +static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos) +{ +#define STREAMING_IS_FINISHED 0 +#define BUFFERING_MAX_PER 100 + + GstQuery *query = NULL; + + return_val_if_fail( player && + player->pipeline && + player->pipeline->mainbin, + MM_ERROR_PLAYER_NOT_INITIALIZED ); + + return_val_if_fail( start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT ); + + if (!MMPLAYER_IS_HTTP_STREAMING ( player )) + { + /* and rtsp is not ready yet. */ + debug_warning ( "it's only used for http streaming case.\n" ); + return MM_ERROR_NONE; + } + + *start_pos = 0; + *stop_pos = 0; + + switch ( format ) + { + case MM_PLAYER_POS_FORMAT_PERCENT : + { + gint start_per = -1, stop_per = -1; + gint64 buffered_total = 0; + + unsigned long position = 0; + guint curr_size_bytes = 0; + gint64 buffering_left = -1; + gint buffered_sec = -1; + + gint64 content_duration = player->duration; + guint64 content_size = player->http_content_size; + + if (content_duration > 0) + { + if (!__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) + { + debug_log ("[Time] pos %d ms / dur %d sec / %lld bytes", position, (guint)(content_duration/GST_SECOND), content_size); + start_per = 100 * (position*GST_MSECOND) / content_duration; + + /* buffered size info from multiqueue */ + if (player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) + { + g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst), "curr-size-bytes", &curr_size_bytes, NULL); + debug_log ("[MQ] curr_size_bytes = %d", curr_size_bytes); + + buffered_total += curr_size_bytes; + } + + /* buffered size info from queue2 */ + if (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) + { + query = gst_query_new_buffering ( GST_FORMAT_BYTES ); + if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) + { + GstBufferingMode mode; + gint byte_in_rate = 0, byte_out_rate = 0; + gint64 start_byte = 0, stop_byte = 0; + guint num_of_ranges = 0; + guint idx = 0; + + num_of_ranges = gst_query_get_n_buffering_ranges(query); + for ( idx=0 ; idx0)?((guint)(content_size/dur_sec)):(0); + + if (avg_byterate > 0) + buffered_sec = (gint)(buffered_total/avg_byterate); + else if (player->total_maximum_bitrate > 0) + buffered_sec = (gint)(GET_BIT_FROM_BYTE(buffered_total)/(gint64)player->total_maximum_bitrate); + else if (player->total_bitrate > 0) + buffered_sec = (gint)(GET_BIT_FROM_BYTE(buffered_total)/(gint64)player->total_bitrate); + + if ((buffered_sec >= 0) && (dur_sec > 0)) + stop_per = start_per + (100 * buffered_sec / dur_sec); + } + + debug_log ("[Buffered Total] %lld bytes, %d sec, per %d~%d\n", buffered_total, buffered_sec, start_per, stop_per); + } + } + + if (((buffered_total == 0) || (start_per < 0) || (stop_per < 0)) && + (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) + { + query = gst_query_new_buffering ( GST_FORMAT_PERCENT ); + if ( gst_element_query ( player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query ) ) + { + GstFormat format; + gint64 range_start_per = -1, range_stop_per = -1; + + gst_query_parse_buffering_range ( query, &format, &range_start_per, &range_stop_per, NULL ); + + debug_log ("[Q2] range start %" G_GINT64_FORMAT " ~ stop %" G_GINT64_FORMAT "\n", range_start_per , range_stop_per); + + if (range_start_per != -1) + start_per = (gint)(100 * range_start_per / GST_FORMAT_PERCENT_MAX); + + if (range_stop_per != -1) + stop_per = (gint)(100 * range_stop_per / GST_FORMAT_PERCENT_MAX); + } + gst_query_unref (query); + } + + if ( start_per > 0) + *start_pos = (start_per < 100)?(start_per):(100); + else + *start_pos = 0; + + if ( stop_per > 0) + *stop_pos = (stop_per < 100)?(stop_per):(100); + else + *stop_pos = 0; + + break; + } + case MM_PLAYER_POS_FORMAT_TIME : + debug_warning ( "Time format is not supported yet.\n" ); + break; + + default : + break; + } + + debug_log("current buffer position : %lu~%lu \n", *start_pos, *stop_pos ); + + return MM_ERROR_NONE; +} + +static int +__gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param) // @ +{ + MMPLAYER_FENTER(); + + if ( !player ) + { + debug_warning("set_message_callback is called with invalid player handle\n"); + return MM_ERROR_PLAYER_NOT_INITIALIZED; + } + + player->msg_cb = callback; + player->msg_cb_param = user_param; + + debug_log("msg_cb : %p msg_cb_param : %p\n", callback, user_param); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data) // @ +{ + int ret = MM_ERROR_PLAYER_INVALID_URI; + char *path = NULL; + + MMPLAYER_FENTER(); + + return_val_if_fail ( uri , FALSE); + return_val_if_fail ( data , FALSE); + return_val_if_fail ( ( strlen(uri) <= MM_MAX_URL_LEN ), FALSE ); + + memset(data, 0, sizeof(MMPlayerParseProfile)); + + if ((path = strstr(uri, "file://"))) + { + int file_stat = MM_ERROR_NONE; + + file_stat = util_exist_file_path(path + 7); + + if (file_stat == MM_ERROR_NONE) + { + strncpy(data->uri, path, MM_MAX_URL_LEN-1); + + if ( util_is_sdp_file ( path ) ) + { + debug_log("uri is actually a file but it's sdp file. giving it to rtspsrc\n"); + data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP; + } + else + { + data->uri_type = MM_PLAYER_URI_TYPE_FILE; + } + ret = MM_ERROR_NONE; + } + else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) + { + data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION; + } + else + { + debug_warning("could access %s.\n", path); + } + } + else if ((path = strstr(uri, "es_buff://"))) + { + if (strlen(path)) + { + strcpy(data->uri, uri); + data->uri_type = MM_PLAYER_URI_TYPE_ES_BUFF; + ret = MM_ERROR_NONE; + } + } + else if ((path = strstr(uri, "buff://"))) + { + data->uri_type = MM_PLAYER_URI_TYPE_BUFF; + ret = MM_ERROR_NONE; + } + else if ((path = strstr(uri, "rtsp://"))) + { + if (strlen(path)) { + if((path = strstr(uri, "/wfd1.0/"))) { + strcpy(data->uri, uri); + data->uri_type = MM_PLAYER_URI_TYPE_URL_WFD; + ret = MM_ERROR_NONE; + debug_log("uri is actually a wfd client path. giving it to wfdrtspsrc\n"); + } + else { + strcpy(data->uri, uri); + data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP; + ret = MM_ERROR_NONE; + } + } + } + else if ((path = strstr(uri, "http://"))) + { + if (strlen(path)) { + strcpy(data->uri, uri); +#ifdef MM_SMOOTH_STREAMING + if (g_str_has_suffix (g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") || + g_str_has_suffix (g_ascii_strdown(uri, strlen(uri)), ".isml/manifest")) + { + data->uri_type = MM_PLAYER_URI_TYPE_SS; + } + else +#endif + data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP; + + ret = MM_ERROR_NONE; + } + } + else if ((path = strstr(uri, "https://"))) + { + if (strlen(path)) { + strcpy(data->uri, uri); +#ifdef MM_SMOOTH_STREAMING + if (g_str_has_suffix (g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") || + g_str_has_suffix (g_ascii_strdown(uri, strlen(uri)), ".isml/manifest")) + { + data->uri_type = MM_PLAYER_URI_TYPE_SS; + } +#endif + data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP; + + ret = MM_ERROR_NONE; + } + } + else if ((path = strstr(uri, "rtspu://"))) + { + if (strlen(path)) { + strcpy(data->uri, uri); + data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP; + ret = MM_ERROR_NONE; + } + } + else if ((path = strstr(uri, "rtspr://"))) + { + strcpy(data->uri, path); + char *separater =strstr(path, "*"); + + if (separater) { + int urgent_len = 0; + char *urgent = separater + strlen("*"); + + if ((urgent_len = strlen(urgent))) { + data->uri[strlen(path) - urgent_len - strlen("*")] = '\0'; + strcpy(data->urgent, urgent); + data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP; + ret = MM_ERROR_NONE; + } + } + } + else if ((path = strstr(uri, "mms://"))) + { + if (strlen(path)) { + strcpy(data->uri, uri); + data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS; + ret = MM_ERROR_NONE; + } + } + else if ((path = strstr(uri, "mem://"))) + { + if (strlen(path)) { + int mem_size = 0; + char *buffer = NULL; + char *seperator = strchr(path, ','); + char ext[100] = {0,}, size[100] = {0,}; + + if (seperator) { + if ((buffer = strstr(path, "ext="))) { + buffer += strlen("ext="); + + if (strlen(buffer)) { + strcpy(ext, buffer); + + if ((seperator = strchr(ext, ',')) + || (seperator = strchr(ext, ' ')) + || (seperator = strchr(ext, '\0'))) { + seperator[0] = '\0'; + } + } + } + + if ((buffer = strstr(path, "size="))) { + buffer += strlen("size="); + + if (strlen(buffer) > 0) { + strcpy(size, buffer); + + if ((seperator = strchr(size, ',')) + || (seperator = strchr(size, ' ')) + || (seperator = strchr(size, '\0'))) { + seperator[0] = '\0'; + } + + mem_size = atoi(size); + } + } + } + + debug_log("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param); + if ( mem_size && param) + { + data->mem = param; + data->mem_size = mem_size; + data->uri_type = MM_PLAYER_URI_TYPE_MEM; + ret = MM_ERROR_NONE; + } + } + } + else + { + int file_stat = MM_ERROR_NONE; + + file_stat = util_exist_file_path(uri); + + /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */ + if (file_stat == MM_ERROR_NONE) + { + g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", uri); + + if ( util_is_sdp_file( (char*)uri ) ) + { + debug_log("uri is actually a file but it's sdp file. giving it to rtspsrc\n"); + data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP; + } + else + { + data->uri_type = MM_PLAYER_URI_TYPE_FILE; + } + ret = MM_ERROR_NONE; + } + else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) + { + data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION; + } + else + { + debug_error ("invalid uri, could not play..\n"); + data->uri_type = MM_PLAYER_URI_TYPE_NONE; + } + } + + if (data->uri_type == MM_PLAYER_URI_TYPE_NONE) { + ret = MM_ERROR_PLAYER_FILE_NOT_FOUND; + } else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION){ + ret = MM_ERROR_PLAYER_PERMISSION_DENIED; + } + + /* dump parse result */ + secure_debug_warning("incomming uri : %s\n", uri); + debug_log("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n", + data->uri_type, data->mem, data->mem_size, data->urgent); + + MMPLAYER_FLEAVE(); + + return ret; +} + +gboolean _asm_postmsg(gpointer *data) +{ + mm_player_t* player = (mm_player_t*)data; + MMMessageParamType msg = {0, }; + + MMPLAYER_FENTER(); + return_val_if_fail ( player, FALSE ); + debug_warning("get notified"); + + if ((player->cmd == MMPLAYER_COMMAND_DESTROY) || + (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) + { + debug_warning("dispatched"); + return FALSE; + } + + + msg.union_type = MM_MSG_UNION_CODE; + msg.code = player->sound_focus.focus_changed_msg; + +#if 0 // should remove + if (player->sm.event_src == ASM_EVENT_SOURCE_RESUMABLE_CANCELED) + { + /* fill the message with state of player */ + msg.state.current = MMPLAYER_CURRENT_STATE(player); + MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg); + player->resumable_cancel_id = 0; + } + else +#endif + { + MMPLAYER_POST_MSG( player, MM_MESSAGE_READY_TO_RESUME, &msg); + player->resume_event_id = 0; + } + + debug_warning("dispatched"); + return FALSE; +} + +gboolean _asm_lazy_pause(gpointer *data) +{ + mm_player_t* player = (mm_player_t*)data; + int ret = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, FALSE ); + + if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING) + { + debug_log ("Ready to proceed lazy pause\n"); + ret = _mmplayer_pause((MMHandleType)player); + if(MM_ERROR_NONE != ret) + { + debug_error("MMPlayer pause failed in ASM callback lazy pause\n"); + } + } + else + { + debug_log ("Invalid state to proceed lazy pause\n"); + } + + /* unset mute */ + if (player->pipeline && player->pipeline->audiobin) + g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL); + + player->sound_focus.by_asm_cb = FALSE; //should be reset here + + MMPLAYER_FLEAVE(); + + return FALSE; +} + +static gboolean +__mmplayer_can_do_interrupt(mm_player_t *player) +{ + if (!player || !player->pipeline || !player->attrs) + { + debug_warning("not initialized"); + goto FAILED; + } + + if ((player->sound_focus.exit_cb) || (player->set_mode.pcm_extraction)) + { + debug_warning("leave from asm cb right now, %d, %d", player->sound_focus.exit_cb, player->set_mode.pcm_extraction); + goto FAILED; + } + + /* check if seeking */ + if (player->doing_seek) + { + MMMessageParamType msg_param; + memset (&msg_param, 0, sizeof(MMMessageParamType)); + msg_param.code = MM_ERROR_PLAYER_SEEK; + player->doing_seek = FALSE; + MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param); + goto FAILED; + } + + /* check other thread */ + if (!g_mutex_trylock(&player->cmd_lock)) + { + debug_warning("locked already, cmd state : %d", player->cmd); + + /* check application command */ + if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) + { + debug_warning("playing.. should wait cmd lock then, will be interrupted"); + g_mutex_lock(&player->cmd_lock); + goto INTERRUPT; + } + debug_warning("nothing to do"); + goto FAILED; + } + else + { + debug_warning("can interrupt immediately"); + goto INTERRUPT; + } + +FAILED: + return FALSE; + +INTERRUPT: + return TRUE; +} + +/* if you want to enable USE_ASM, please check the history get the ASM cb code. */ +static int +__mmplayer_convert_sound_focus_state(gboolean acquire, const char *reason_for_change, MMPlayerFocusChangedMsg *msg) +{ + int ret = MM_ERROR_NONE; + MMPlayerFocusChangedMsg focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN; + + if (strstr(reason_for_change, "alarm")) { + focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_ALARM; + + } else if (strstr(reason_for_change, "notification")) { + focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_NOTIFICATION; + + } else if (strstr(reason_for_change, "emergency")) { + focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_EMERGENCY; + + } else if (strstr(reason_for_change, "call-voice") || + strstr(reason_for_change, "call-video") || + strstr(reason_for_change, "voip") || + strstr(reason_for_change, "ringtone-voip") || + strstr(reason_for_change, "ringtone-call")) { + focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_CALL; + + } else if (strstr(reason_for_change, "media") || + strstr(reason_for_change, "radio") || + strstr(reason_for_change, "loopback") || + strstr(reason_for_change, "system") || + strstr(reason_for_change, "voice-information") || + strstr(reason_for_change, "voice-recognition")) { + focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_MEDIA; + + } else { + ret = MM_ERROR_INVALID_ARGUMENT; + debug_warning("not supported reason(%s), err(0x%08x)", reason_for_change, ret); + goto DONE; + } + + if (acquire && (focus_msg != MM_PLAYER_FOCUS_CHANGED_BY_MEDIA)) + { + /* can acqurie */ + focus_msg = MM_PLAYER_FOCUS_CHANGED_COMPLETED; + } + + debug_log("converted from reason(%s) to msg(%d)", reason_for_change, focus_msg); + *msg = focus_msg; + +DONE: + return ret; +} + +/* FIXME: will be updated with new funct */ +void __mmplayer_sound_focus_watch_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state, + const char *reason_for_change, const char *additional_info, void *user_data) +{ + mm_player_t* player = (mm_player_t*) user_data; + int result = MM_ERROR_NONE; + MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN; + + debug_warning("focus watch notified"); + + if (!__mmplayer_can_do_interrupt(player)) + { + debug_warning("no need to interrupt, so leave"); + goto EXIT; + } + + if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) + { + debug_warning("flags is UNINTERRUPTIBLE. do nothing."); + goto EXIT; + } + + debug_warning("watch: state: %d, focus_type : %d, reason_for_change : %s", + focus_state, focus_type, (reason_for_change?reason_for_change:"N/A")); + + player->sound_focus.cb_pending = TRUE; + player->sound_focus.by_asm_cb = TRUE; + + if (focus_state == FOCUS_IS_ACQUIRED) + { + debug_warning("watch: FOCUS_IS_ACQUIRED"); + if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg)) + { + player->sound_focus.focus_changed_msg = (int)msg; + } + + if (strstr(reason_for_change, "call") || + strstr(reason_for_change, "voip") || /* FIXME: to check */ + strstr(reason_for_change, "alarm") || + strstr(reason_for_change, "media")) + { + if (!MMPLAYER_IS_RTSP_STREAMING(player)) + { + // hold 0.7 second to excute "fadedown mute" effect + debug_warning ("do fade down->pause->undo fade down"); + + __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT); + + result = _mmplayer_pause((MMHandleType)player); + if (result != MM_ERROR_NONE) + { + debug_warning("fail to set Pause state by asm"); + goto EXIT; + } + __mmplayer_undo_sound_fadedown(player); + } + else + { + /* rtsp should connect again in specific network becasue tcp session can't be kept any more */ + _mmplayer_unrealize((MMHandleType)player); + } + } + else + { + debug_warning ("pause immediately"); + result = _mmplayer_pause((MMHandleType)player); + if (result != MM_ERROR_NONE) + { + debug_warning("fail to set Pause state by asm"); + goto EXIT; + } + } + } + else if (focus_state == FOCUS_IS_RELEASED) + { + debug_warning("FOCUS_IS_RELEASED: Got msg from asm to resume"); + player->sound_focus.antishock = TRUE; + player->sound_focus.by_asm_cb = FALSE; + + if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg)) + { + player->sound_focus.focus_changed_msg = (int)msg; + } + + //ASM server is single thread daemon. So use g_idle_add() to post resume msg + player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player); + goto DONE; + } + else + { + debug_warning("unknown focus state %d", focus_state); + } + +DONE: + player->sound_focus.by_asm_cb = FALSE; + player->sound_focus.cb_pending = FALSE; + MMPLAYER_CMD_UNLOCK( player ); + +EXIT: + debug_warning("dispatched"); + return; +} + +void +__mmplayer_sound_focus_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state, + const char *reason_for_change, const char *additional_info, void *user_data) +{ + mm_player_t* player = (mm_player_t*) user_data; + int result = MM_ERROR_NONE; + gboolean lazy_pause = FALSE; + MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN; + + debug_warning("get focus notified"); + + if (!__mmplayer_can_do_interrupt(player)) + { + debug_warning("no need to interrupt, so leave"); + goto EXIT; + } + + if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) + { + debug_warning("flags is UNINTERRUPTIBLE. do nothing."); + goto EXIT; + } + + debug_warning("state: %d, focus_type : %d, reason_for_change : %s", + focus_state, focus_type, (reason_for_change?reason_for_change:"N/A")); + + player->sound_focus.cb_pending = TRUE; + player->sound_focus.by_asm_cb = TRUE; +// player->sound_focus.event_src = event_src; + +#if 0 + /* first, check event source */ + if(event_src == ASM_EVENT_SOURCE_EARJACK_UNPLUG) + { + int stop_by_asm = 0; + mm_attrs_get_int_by_name(player->attrs, "sound_stop_when_unplugged", &stop_by_asm); + if (!stop_by_asm) + goto DONE; + } + else if (event_src == ASM_EVENT_SOURCE_RESOURCE_CONFLICT) + { + /* can use video overlay simultaneously */ + /* video resource conflict */ + if(player->pipeline->videobin) + { + debug_log("video conflict but, can support multiple video"); + result = _mmplayer_pause((MMHandleType)player); + cb_res = ASM_CB_RES_PAUSE; + } + else if (player->pipeline->audiobin) + { + debug_log("audio resource conflict"); + result = _mmplayer_pause((MMHandleType)player); + if (result != MM_ERROR_NONE) + { + debug_warning("fail to set pause by asm"); + } + cb_res = ASM_CB_RES_PAUSE; + } + goto DONE; + } +#if 0 // should remove + else if (event_src == ASM_EVENT_SOURCE_RESUMABLE_CANCELED) + { + debug_warning("Got msg from asm for resumable canceled.\n"); + player->sound_focus.antishock = TRUE; + player->sound_focus.by_asm_cb = FALSE; + + player->resumable_cancel_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player); + cb_res = ASM_CB_RES_IGNORE; + goto DONE; + } +#endif +#endif + + if (focus_state == FOCUS_IS_RELEASED) + { + debug_warning("FOCUS_IS_RELEASED"); + + if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg)) + { + player->sound_focus.focus_changed_msg = (int)msg; + } + + if (strstr(reason_for_change, "call") || + strstr(reason_for_change, "voip") || /* FIXME: to check */ + strstr(reason_for_change, "alarm") || + strstr(reason_for_change, "media")) + { + if (!MMPLAYER_IS_RTSP_STREAMING(player)) + { + //hold 0.7 second to excute "fadedown mute" effect + debug_warning ("do fade down->pause->undo fade down"); + + __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT); + + result = _mmplayer_pause((MMHandleType)player); + if (result != MM_ERROR_NONE) + { + debug_warning("fail to set Pause state by asm"); + goto EXIT; + } + __mmplayer_undo_sound_fadedown(player); + } + else + { + /* rtsp should connect again in specific network becasue tcp session can't be kept any more */ + _mmplayer_unrealize((MMHandleType)player); + } + } +#if 0 +#ifdef USE_LAZY_PAUSE // if enabled, should consider event id and context when removed + else if(event_src == ASM_EVENT_SOURCE_OTHER_PLAYER_APP) + { + lazy_pause = TRUE; // return as soon as possible, for fast start of other app + + if ( player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_SINK].gst ) + g_object_set( player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "mute", 2, NULL); + + player->lazy_pause_event_id = g_timeout_add(LAZY_PAUSE_TIMEOUT_MSEC, (GSourceFunc)_asm_lazy_pause, (gpointer)player); + debug_warning ("set lazy pause timer (id=[%d], timeout=[%d ms])", player->lazy_pause_event_id, LAZY_PAUSE_TIMEOUT_MSEC); + } +#endif +#endif + else + { + debug_warning ("pause immediately"); + result = _mmplayer_pause((MMHandleType)player); + if (result != MM_ERROR_NONE) + { + debug_warning("fail to set Pause state by asm"); + goto EXIT; + } + } + } + else if (focus_state == FOCUS_IS_ACQUIRED) + { + debug_warning("FOCUS_IS_ACQUIRED: Got msg from asm to resume"); + player->sound_focus.antishock = TRUE; + player->sound_focus.by_asm_cb = FALSE; + + if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg)) + { + player->sound_focus.focus_changed_msg = (int)msg; + } + + //ASM server is single thread daemon. So use g_idle_add() to post resume msg + player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player); + goto DONE; + } + else + { + debug_warning("unknown focus state %d", focus_state); + } + +DONE: + if ( !lazy_pause ) + { + player->sound_focus.by_asm_cb = FALSE; + } + player->sound_focus.cb_pending = FALSE; + MMPLAYER_CMD_UNLOCK( player ); + +EXIT: + debug_warning("dispatched"); + return; +} + + +int +_mmplayer_create_player(MMHandleType handle) // @ +{ + mm_player_t* player = MM_PLAYER_CAST(handle); + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + /* initialize player state */ + MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE; + MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE; + MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE; + MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE; + + /* check current state */ + MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_CREATE ); + + /* construct attributes */ + player->attrs = _mmplayer_construct_attribute(handle); + + if ( !player->attrs ) + { + debug_error("Failed to construct attributes\n"); + goto ERROR; + } + + /* initialize gstreamer with configured parameter */ + if ( ! __mmplayer_init_gstreamer(player) ) + { + debug_error("Initializing gstreamer failed\n"); + goto ERROR; + } + + /* initialize factories if not using decodebin */ + if( player->factories == NULL ) + __mmplayer_init_factories(player); + + /* create lock. note that g_tread_init() has already called in gst_init() */ + g_mutex_init(&player->fsink_lock); + + /* create repeat mutex */ + g_mutex_init(&player->repeat_thread_mutex); + + /* create repeat cond */ + g_cond_init(&player->repeat_thread_cond); + + /* create repeat thread */ + player->repeat_thread = + g_thread_try_new ("repeat_thread", __mmplayer_repeat_thread, (gpointer)player, NULL); + + + /* create next play mutex */ + g_mutex_init(&player->next_play_thread_mutex); + + /* create next play cond */ + g_cond_init(&player->next_play_thread_cond); + + /* create next play thread */ + player->next_play_thread = + g_thread_try_new ("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL); + if ( ! player->next_play_thread ) + { + debug_error("failed to create next play thread"); + goto ERROR; + } + + if ( MM_ERROR_NONE != _mmplayer_initialize_video_capture(player)) + { + debug_error("failed to initialize video capture\n"); + goto ERROR; + } + + /* register to asm */ + if ( MM_ERROR_NONE != _mmplayer_sound_register(&player->sound_focus, + (mm_sound_focus_changed_cb)__mmplayer_sound_focus_callback, + (mm_sound_focus_changed_watch_cb)__mmplayer_sound_focus_watch_callback, + (void*)player) ) + + { + /* NOTE : we are dealing it as an error since we cannot expect it's behavior */ + debug_error("failed to register asm server\n"); + return MM_ERROR_POLICY_INTERNAL; + } +#if 0 //need to change and test + /* to add active device callback */ + if ( MM_ERROR_NONE != mm_sound_add_device_information_changed_callback(MM_SOUND_DEVICE_STATE_ACTIVATED_FLAG, __mmplayer_sound_device_info_changed_cb_func, (void*)player)) + { + debug_error("failed mm_sound_add_device_information_changed_callback \n"); + } +#endif + if (MMPLAYER_IS_HTTP_PD(player)) + { + player->pd_downloader = NULL; + player->pd_file_save_path = NULL; + } + + player->streaming_type = STREAMING_SERVICE_NONE; + + /* give default value of audio effect setting */ + player->sound.volume = MM_VOLUME_FACTOR_DEFAULT; + player->playback_rate = DEFAULT_PLAYBACK_RATE; + + player->play_subtitle = FALSE; + player->use_textoverlay = FALSE; + player->play_count = 0; + player->use_decodebin = TRUE; + player->ignore_asyncdone = FALSE; + player->use_deinterleave = FALSE; + player->max_audio_channels = 0; + player->video_share_api_delta = 0; + player->video_share_clock_delta = 0; + player->has_closed_caption = FALSE; + + __mmplayer_post_proc_reset(player); + + if (player->ini.dump_element_keyword[0][0] == '\0') + { + player->ini.set_dump_element_flag= FALSE; + } + else + { + player->ini.set_dump_element_flag = TRUE; + } + + /* set player state to null */ + MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout; + MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_NULL ); + + return MM_ERROR_NONE; + +ERROR: + /* free lock */ + g_mutex_clear(&player->fsink_lock ); + + /* free thread */ + if ( player->repeat_thread ) + { + player->repeat_thread_exit = TRUE; + g_cond_signal( &player->repeat_thread_cond ); + + g_thread_join( player->repeat_thread ); + player->repeat_thread = NULL; + + g_mutex_clear(&player->repeat_thread_mutex ); + + g_cond_clear (&player->repeat_thread_cond ); + } + /* clear repeat thread mutex/cond if still alive + * this can happen if only thread creating has failed + */ + g_mutex_clear(&player->repeat_thread_mutex ); + g_cond_clear ( &player->repeat_thread_cond ); + + /* free next play thread */ + if ( player->next_play_thread ) + { + player->next_play_thread_exit = TRUE; + g_cond_signal( &player->next_play_thread_cond ); + + g_thread_join( player->next_play_thread ); + player->next_play_thread = NULL; + + g_mutex_clear(&player->next_play_thread_mutex ); + + g_cond_clear ( &player->next_play_thread_cond ); + } + /* clear next play thread mutex/cond if still alive + * this can happen if only thread creating has failed + */ + g_mutex_clear(&player->next_play_thread_mutex ); + + g_cond_clear ( &player->next_play_thread_cond ); + + /* release attributes */ + _mmplayer_deconstruct_attribute(handle); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_PLAYER_INTERNAL; +} + +static gboolean +__mmplayer_init_gstreamer(mm_player_t* player) // @ +{ + static gboolean initialized = FALSE; + static const int max_argc = 50; + gint* argc = NULL; + gchar** argv = NULL; + gchar** argv2 = NULL; + GError *err = NULL; + int i = 0; + int arg_count = 0; + + if ( initialized ) + { + debug_log("gstreamer already initialized.\n"); + return TRUE; + } + + /* alloc */ + argc = malloc( sizeof(int) ); + argv = malloc( sizeof(gchar*) * max_argc ); + argv2 = malloc( sizeof(gchar*) * max_argc ); + + if ( !argc || !argv || !argv2 ) + goto ERROR; + + memset( argv, 0, sizeof(gchar*) * max_argc ); + memset( argv2, 0, sizeof(gchar*) * max_argc ); + + /* add initial */ + *argc = 1; + argv[0] = g_strdup( "mmplayer" ); + + /* add gst_param */ + for ( i = 0; i < 5; i++ ) /* FIXIT : num of param is now fixed to 5. make it dynamic */ + { + if ( strlen( player->ini.gst_param[i] ) > 0 ) + { + argv[*argc] = g_strdup( player->ini.gst_param[i] ); + (*argc)++; + } + } + + /* we would not do fork for scanning plugins */ + argv[*argc] = g_strdup("--gst-disable-registry-fork"); + (*argc)++; + + /* check disable registry scan */ + if ( player->ini.skip_rescan ) + { + argv[*argc] = g_strdup("--gst-disable-registry-update"); + (*argc)++; + } + + /* check disable segtrap */ + if ( player->ini.disable_segtrap ) + { + argv[*argc] = g_strdup("--gst-disable-segtrap"); + (*argc)++; + } + + debug_log("initializing gstreamer with following parameter\n"); + debug_log("argc : %d\n", *argc); + arg_count = *argc; + + for ( i = 0; i < arg_count; i++ ) + { + argv2[i] = argv[i]; + debug_log("argv[%d] : %s\n", i, argv2[i]); + } + + + /* initializing gstreamer */ + if ( ! gst_init_check (argc, &argv, &err)) + { + debug_error("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred"); + if (err) + { + g_error_free (err); + } + + goto ERROR; + } + /* release */ + for ( i = 0; i < arg_count; i++ ) + { + //debug_log("release - argv[%d] : %s\n", i, argv2[i]); + MMPLAYER_FREEIF( argv2[i] ); + } + + MMPLAYER_FREEIF( argv ); + MMPLAYER_FREEIF( argv2 ); + MMPLAYER_FREEIF( argc ); + + /* done */ + initialized = TRUE; + + return TRUE; + +ERROR: + + /* release */ + for ( i = 0; i < arg_count; i++ ) + { + debug_log("free[%d] : %s\n", i, argv2[i]); + MMPLAYER_FREEIF( argv2[i] ); + } + + MMPLAYER_FREEIF( argv ); + MMPLAYER_FREEIF( argv2 ); + MMPLAYER_FREEIF( argc ); + + return FALSE; +} + +int +__mmplayer_destroy_streaming_ext(mm_player_t* player) +{ + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + if (player->pd_downloader) + { + _mmplayer_unrealize_pd_downloader((MMHandleType)player); + MMPLAYER_FREEIF(player->pd_downloader); + } + + if (MMPLAYER_IS_HTTP_PD(player)) + { + _mmplayer_destroy_pd_downloader((MMHandleType)player); + MMPLAYER_FREEIF(player->pd_file_save_path); + } + + return MM_ERROR_NONE; +} + +int +_mmplayer_destroy(MMHandleType handle) // @ +{ + mm_player_t* player = MM_PLAYER_CAST(handle); + + MMPLAYER_FENTER(); + + /* check player handle */ + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + /* destroy can called at anytime */ + MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_DESTROY ); + + __mmplayer_destroy_streaming_ext(player); + + /* release repeat thread */ + if ( player->repeat_thread ) + { + player->repeat_thread_exit = TRUE; + g_cond_signal( &player->repeat_thread_cond ); + + debug_log("waitting for repeat thread exit\n"); + g_thread_join ( player->repeat_thread ); + g_mutex_clear(&player->repeat_thread_mutex ); + g_cond_clear (&player->repeat_thread_cond ); + debug_log("repeat thread released\n"); + } + + /* release next play thread */ + if ( player->next_play_thread ) + { + player->next_play_thread_exit = TRUE; + g_cond_signal( &player->next_play_thread_cond ); + + debug_log("waitting for next play thread exit\n"); + g_thread_join ( player->next_play_thread ); + g_mutex_clear(&player->next_play_thread_mutex ); + g_cond_clear(&player->next_play_thread_cond ); + debug_log("next play thread released\n"); + } + + _mmplayer_release_video_capture(player); + + /* flush any pending asm_cb */ + if (player->sound_focus.cb_pending) + { + /* set a flag for make sure asm_cb to be returned immediately */ + debug_warning("asm cb has pending state"); + player->sound_focus.exit_cb = TRUE; + + /* make sure to release any pending asm_cb which locked by cmd_lock */ + MMPLAYER_CMD_UNLOCK(player); + sched_yield(); + MMPLAYER_CMD_LOCK(player); + } + + /* withdraw asm */ + if ( MM_ERROR_NONE != _mmplayer_sound_unregister(&player->sound_focus) ) + { + debug_error("failed to deregister asm server\n"); + } + +#ifdef USE_LAZY_PAUSE + if (player->lazy_pause_event_id) + { + __mmplayer_remove_g_source_from_context(player->context.global_default, player->lazy_pause_event_id); + player->lazy_pause_event_id = 0; + } +#endif + + if (player->resume_event_id) + { + g_source_remove (player->resume_event_id); + player->resume_event_id = 0; + } + + if (player->resumable_cancel_id) + { + g_source_remove (player->resumable_cancel_id); + player->resumable_cancel_id = 0; + } + + /* release pipeline */ + if ( MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline( player ) ) + { + debug_error("failed to destory pipeline\n"); + return MM_ERROR_PLAYER_INTERNAL; + } + + if (player->is_external_subtitle_present && player->subtitle_language_list) + { + g_list_free (player->subtitle_language_list); + player->subtitle_language_list = NULL; + } + + __mmplayer_release_dump_list (player->dump_list); + + /* release miscellaneous information. + these info needs to be released after pipeline is destroyed. */ + __mmplayer_release_misc_post( player ); + + /* release attributes */ + _mmplayer_deconstruct_attribute( handle ); + + /* release factories */ + __mmplayer_release_factories( player ); + + /* release lock */ + g_mutex_clear(&player->fsink_lock ); + + g_mutex_clear(&player->msg_cb_lock ); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +int +__mmplayer_realize_streaming_ext(mm_player_t* player) +{ + int ret = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + if (MMPLAYER_IS_HTTP_PD(player)) + { + gboolean bret = FALSE; + + player->pd_downloader = _mmplayer_create_pd_downloader(); + if ( !player->pd_downloader ) + { + debug_error ("Unable to create PD Downloader..."); + ret = MM_ERROR_PLAYER_NO_FREE_SPACE; + } + + bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst); + + if (FALSE == bret) + { + debug_error ("Unable to create PD Downloader..."); + ret = MM_ERROR_PLAYER_NOT_INITIALIZED; + } + } + + MMPLAYER_FLEAVE(); + return ret; +} + +int +_mmplayer_realize(MMHandleType hplayer) // @ +{ + mm_player_t* player = (mm_player_t*)hplayer; + char *uri =NULL; + void *param = NULL; + int application_pid = -1; + gboolean update_registry = FALSE; + MMHandleType attrs = 0; + int ret = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + /* check player handle */ + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ) + + /* check current state */ + MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_REALIZE ); + + attrs = MMPLAYER_GET_ATTRS(player); + if ( !attrs ) + { + debug_error("fail to get attributes.\n"); + return MM_ERROR_PLAYER_INTERNAL; + } + + mm_attrs_get_int_by_name(attrs, "sound_application_pid", &application_pid ); + player->sound_focus.pid = application_pid; + + mm_attrs_get_string_by_name(attrs, "profile_uri", &uri); + mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m); + + ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile); + + if (ret != MM_ERROR_NONE) + { + debug_error("failed to parse profile\n"); + return ret; + } + + /* FIXIT : we can use thouse in player->profile directly */ + if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) + { + player->mem_buf.buf = (char *)player->profile.mem; + player->mem_buf.len = player->profile.mem_size; + player->mem_buf.offset = 0; + } + + if (player->profile.uri_type == MM_PLAYER_URI_TYPE_ES_BUFF) + { + if (strstr(uri, "es_buff://push_mode")) + { + player->es_player_push_mode = TRUE; + } + else + { + player->es_player_push_mode = FALSE; + } + } + + if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) + { + debug_warning("mms protocol is not supported format.\n"); + return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT; + } + + if (MMPLAYER_IS_STREAMING(player)) + MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout; + else + MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout; + + player->smooth_streaming = FALSE; + player->videodec_linked = 0; + player->videosink_linked = 0; + player->audiodec_linked = 0; + player->audiosink_linked = 0; + player->textsink_linked = 0; + player->is_external_subtitle_present = FALSE; + /* set the subtitle ON default */ + player->is_subtitle_off = FALSE; + + /* registry should be updated for downloadable codec */ + mm_attrs_get_int_by_name(attrs, "profile_update_registry", &update_registry); + + if ( update_registry ) + { + debug_log("updating registry...\n"); + gst_update_registry(); + + /* then we have to rebuild factories */ + __mmplayer_release_factories( player ); + __mmplayer_init_factories(player); + } + + /* realize pipeline */ + ret = __gst_realize( player ); + if ( ret != MM_ERROR_NONE ) + { + debug_error("fail to realize the player.\n"); + } + else + { + ret = __mmplayer_realize_streaming_ext(player); + } + + MMPLAYER_FLEAVE(); + + return ret; +} + +int +__mmplayer_unrealize_streaming_ext(mm_player_t *player) +{ + MMPLAYER_FENTER(); + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + /* destroy can called at anytime */ + if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player)) + { + _mmplayer_unrealize_pd_downloader ((MMHandleType)player); + MMPLAYER_FREEIF(player->pd_downloader); + } + + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; +} + +int +_mmplayer_unrealize(MMHandleType hplayer) +{ + mm_player_t* player = (mm_player_t*)hplayer; + int ret = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ) + + /* check current state */ + MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_UNREALIZE ); + + __mmplayer_unrealize_streaming_ext(player); + + /* unrealize pipeline */ + ret = __gst_unrealize( player ); + + /* set asm stop if success */ + if (MM_ERROR_NONE == ret) + { + ret = _mmplayer_sound_release_focus(&player->sound_focus); + if ( ret != MM_ERROR_NONE ) + { + debug_error("failed to release sound focus\n"); + return ret; + } + } + else + { + debug_error("failed and don't change asm state to stop"); + } + + MMPLAYER_FLEAVE(); + + return ret; +} + +int +_mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param) // @ +{ + mm_player_t* player = (mm_player_t*)hplayer; + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + return __gst_set_message_callback(player, callback, user_param); +} + +int +_mmplayer_get_state(MMHandleType hplayer, int* state) // @ +{ + mm_player_t *player = (mm_player_t*)hplayer; + + return_val_if_fail(state, MM_ERROR_INVALID_ARGUMENT); + + *state = MMPLAYER_CURRENT_STATE(player); + + return MM_ERROR_NONE; +} + + +int +_mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume) // @ +{ + mm_player_t* player = (mm_player_t*) hplayer; + GstElement* vol_element = NULL; + int i = 0; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + debug_log("volume [L]=%f:[R]=%f\n", + volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]); + + /* invalid factor range or not */ + for ( i = 0; i < MM_VOLUME_CHANNEL_NUM; i++ ) + { + if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) { + debug_error("Invalid factor! (valid factor:0~1.0)\n"); + return MM_ERROR_INVALID_ARGUMENT; + } + } + + /* not support to set other value into each channel */ + if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT])) + return MM_ERROR_INVALID_ARGUMENT; + + /* Save volume to handle. Currently the first array element will be saved. */ + player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT]; + + /* check pipeline handle */ + if ( ! player->pipeline || ! player->pipeline->audiobin ) + { + debug_log("audiobin is not created yet\n"); + debug_log("but, current stored volume will be set when it's created.\n"); + + /* NOTE : stored volume will be used in create_audiobin + * returning MM_ERROR_NONE here makes application to able to + * set volume at anytime. + */ + return MM_ERROR_NONE; + } + + /* setting volume to volume element */ + vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst; + + if ( vol_element ) + { + debug_log("volume is set [%f]\n", player->sound.volume); + g_object_set(vol_element, "volume", player->sound.volume, NULL); + } + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + + +int +_mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume) +{ + mm_player_t* player = (mm_player_t*) hplayer; + int i = 0; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + return_val_if_fail( volume, MM_ERROR_INVALID_ARGUMENT ); + + /* returning stored volume */ + for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) + volume->level[i] = player->sound.volume; + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + + + +int +_mmplayer_set_mute(MMHandleType hplayer, int mute) // @ +{ + mm_player_t* player = (mm_player_t*) hplayer; + GstElement* vol_element = NULL; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + /* mute value shoud 0 or 1 */ + if ( mute != 0 && mute != 1 ) + { + debug_error("bad mute value\n"); + + /* FIXIT : definitly, we need _BAD_PARAM error code */ + return MM_ERROR_INVALID_ARGUMENT; + } + + player->sound.mute = mute; + + /* just hold mute value if pipeline is not ready */ + if ( !player->pipeline || !player->pipeline->audiobin ) + { + debug_log("pipeline is not ready. holding mute value\n"); + return MM_ERROR_NONE; + } + + vol_element = player->pipeline->audiobin[MMPLAYER_A_SINK].gst; + + /* NOTE : volume will only created when the bt is enabled */ + if ( vol_element ) + { + debug_log("mute : %d\n", mute); + g_object_set(vol_element, "mute", mute, NULL); + } + else + { + debug_log("volume elemnet is not created. using volume in audiosink\n"); + } + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +int +_mmplayer_get_mute(MMHandleType hplayer, int* pmute) // @ +{ + mm_player_t* player = (mm_player_t*) hplayer; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + return_val_if_fail ( pmute, MM_ERROR_INVALID_ARGUMENT ); + + /* just hold mute value if pipeline is not ready */ + if ( !player->pipeline || !player->pipeline->audiobin ) + { + debug_log("pipeline is not ready. returning stored value\n"); + *pmute = player->sound.mute; + return MM_ERROR_NONE; + } + + *pmute = player->sound.mute; + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +int +_mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param) +{ + mm_player_t* player = (mm_player_t*) hplayer; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + player->video_stream_changed_cb = callback; + player->video_stream_changed_cb_user_param = user_param; + debug_log("Handle value is %p : %p\n", player, player->video_stream_changed_cb); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +int +_mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param) +{ + mm_player_t* player = (mm_player_t*) hplayer; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + player->audio_stream_changed_cb = callback; + player->audio_stream_changed_cb_user_param = user_param; + debug_log("Handle value is %p : %p\n", player, player->audio_stream_changed_cb); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +int +_mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param) // @ +{ + mm_player_t* player = (mm_player_t*) hplayer; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + player->audio_stream_render_cb_ex = callback; + player->audio_stream_cb_user_param = user_param; + player->audio_stream_sink_sync = sync; + debug_log("Audio Stream cb Handle value is %p : %p audio_stream_sink_sync : %d\n", player, player->audio_stream_render_cb_ex, player->audio_stream_sink_sync); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +int +_mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param) // @ +{ + mm_player_t* player = (mm_player_t*) hplayer; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + player->video_stream_cb = callback; + player->video_stream_cb_user_param = user_param; + player->use_video_stream = TRUE; + debug_log("Stream cb Handle value is %p : %p\n", player, player->video_stream_cb); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +int +_mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @ +{ + mm_player_t* player = (mm_player_t*) hplayer; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + player->audio_stream_cb = callback; + player->audio_stream_cb_user_param = user_param; + debug_log("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +// set prepare size +int +_mmplayer_set_prepare_buffering_time(MMHandleType hplayer, int second) +{ + mm_player_t* player = (mm_player_t*) hplayer; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) + return MM_ERROR_PLAYER_INVALID_STATE; + + debug_log("pre buffer size : %d sec\n", second); + + if ( second <= 0 ) + { + debug_error("bad size value\n"); + return MM_ERROR_INVALID_ARGUMENT; + } + + if (player->streamer == NULL) + { + player->streamer = __mm_player_streaming_create(); + __mm_player_streaming_initialize(player->streamer); + } + + player->streamer->buffering_req.initial_second = second; + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +// set runtime mode +int +_mmplayer_set_runtime_buffering_mode(MMHandleType hplayer, MMPlayerBufferingMode mode, int second) +{ + mm_player_t* player = (mm_player_t*) hplayer; + + MMPLAYER_FENTER(); + + return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + debug_log("mode %d\n", mode); + + if ((mode < 0) || (mode > MM_PLAYER_BUFFERING_MODE_MAX) || + ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) && (second <= 0))) + return MM_ERROR_INVALID_ARGUMENT; + + if (player->streamer == NULL) + { + player->streamer = __mm_player_streaming_create(); + __mm_player_streaming_initialize(player->streamer); + } + + player->streamer->buffering_req.mode = mode; + + if ((second > 0) && + ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) || + (mode == MM_PLAYER_BUFFERING_MODE_ADAPTIVE))) + player->streamer->buffering_req.runtime_second = second; + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +int +_mmplayer_set_videoframe_render_error_cb(MMHandleType hplayer, mm_player_video_frame_render_error_callback callback, void *user_param) // @ +{ + mm_player_t* player = (mm_player_t*) hplayer; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + return_val_if_fail ( callback, MM_ERROR_INVALID_ARGUMENT ); + + player->video_frame_render_error_cb = callback; + player->video_frame_render_error_cb_user_param = user_param; + + debug_log("Video frame render error cb Handle value is %p : %p\n", player, player->video_frame_render_error_cb); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +int +__mmplayer_start_streaming_ext(mm_player_t *player) +{ + gint ret = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + if (MMPLAYER_IS_HTTP_PD(player)) + { + if ( !player->pd_downloader ) + { + ret = __mmplayer_realize_streaming_ext(player); + + if ( ret != MM_ERROR_NONE) + { + debug_error ("failed to realize streaming ext\n"); + return ret; + } + } + + if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) + { + ret = _mmplayer_start_pd_downloader ((MMHandleType)player); + if ( !ret ) + { + debug_error ("ERROR while starting PD...\n"); + return MM_ERROR_PLAYER_NOT_INITIALIZED; + } + ret = MM_ERROR_NONE; + } + } + + MMPLAYER_FLEAVE(); + return ret; +} + +int +_mmplayer_start(MMHandleType hplayer) // @ +{ + mm_player_t* player = (mm_player_t*) hplayer; + gint ret = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + /* check current state */ + MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_START ); + + ret = _mmplayer_sound_acquire_focus(&player->sound_focus); + if ( ret != MM_ERROR_NONE ) + { + debug_error("failed to acquire sound focus.\n"); + return ret; + } + + /* NOTE : we should check and create pipeline again if not created as we destroy + * whole pipeline when stopping in streamming playback + */ + if ( ! player->pipeline ) + { + ret = __gst_realize( player ); + if ( MM_ERROR_NONE != ret ) + { + debug_error("failed to realize before starting. only in streamming\n"); + /* unlock */ + return ret; + } + } + + ret = __mmplayer_start_streaming_ext(player); + if ( ret != MM_ERROR_NONE ) + { + debug_error("failed to start streaming ext \n"); + } + + /* start pipeline */ + ret = __gst_start( player ); + if ( ret != MM_ERROR_NONE ) + { + debug_error("failed to start player.\n"); + } + + MMPLAYER_FLEAVE(); + + return ret; +} + +/* NOTE: post "not supported codec message" to application + * when one codec is not found during AUTOPLUGGING in MSL. + * So, it's separated with error of __mmplayer_gst_callback(). + * And, if any codec is not found, don't send message here. + * Because GST_ERROR_MESSAGE is posted by other plugin internally. + */ +int +__mmplayer_handle_missed_plugin(mm_player_t* player) +{ + MMMessageParamType msg_param; + memset (&msg_param, 0, sizeof(MMMessageParamType)); + gboolean post_msg_direct = FALSE; + + MMPLAYER_FENTER(); + + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + debug_log("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n", + player->not_supported_codec, player->can_support_codec); + + if( player->not_found_demuxer ) + { + msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND; + msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime); + + MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param ); + MMPLAYER_FREEIF(msg_param.data); + + return MM_ERROR_NONE; + } + + if (player->not_supported_codec) + { + if ( player->can_support_codec ) // There is one codec to play + { + post_msg_direct = TRUE; + } + else + { + if ( player->pipeline->audiobin ) // Some content has only PCM data in container. + post_msg_direct = TRUE; + } + + if ( post_msg_direct ) + { + MMMessageParamType msg_param; + memset (&msg_param, 0, sizeof(MMMessageParamType)); + + if ( player->not_supported_codec == MISSING_PLUGIN_AUDIO ) + { + debug_warning("not found AUDIO codec, posting error code to application.\n"); + + msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND; + msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime); + } + else if ( player->not_supported_codec == MISSING_PLUGIN_VIDEO ) + { + debug_warning("not found VIDEO codec, posting error code to application.\n"); + + msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND; + msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime); + } + + MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param ); + + MMPLAYER_FREEIF(msg_param.data); + + return MM_ERROR_NONE; + } + else // no any supported codec case + { + debug_warning("not found any codec, posting error code to application.\n"); + + if ( player->not_supported_codec == MISSING_PLUGIN_AUDIO ) + { + msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND; + msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime); + } + else + { + msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND; + msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime); + } + + MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param ); + + MMPLAYER_FREEIF(msg_param.data); + } + } + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +static void __mmplayer_check_pipeline(mm_player_t* player) +{ + GstState element_state = GST_STATE_VOID_PENDING; + GstState element_pending_state = GST_STATE_VOID_PENDING; + gint timeout = 0; + int ret = MM_ERROR_NONE; + + if (player->gapless.reconfigure) + { + debug_warning("pipeline is under construction.\n"); + + MMPLAYER_PLAYBACK_LOCK(player); + MMPLAYER_PLAYBACK_UNLOCK(player); + + timeout = MMPLAYER_STATE_CHANGE_TIMEOUT ( player ); + + /* wait for state transition */ + ret = gst_element_get_state( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND ); + + if ( ret == GST_STATE_CHANGE_FAILURE ) + { + debug_error("failed to change pipeline state within %d sec\n", timeout ); + } + } +} + +/* NOTE : it should be able to call 'stop' anytime*/ +int +_mmplayer_stop(MMHandleType hplayer) // @ +{ + mm_player_t* player = (mm_player_t*)hplayer; + int ret = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + /* check current state */ + MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_STOP ); + + /* check pipline building state */ + __mmplayer_check_pipeline(player); + player->gapless.start_time = 0; + + /* NOTE : application should not wait for EOS after calling STOP */ + __mmplayer_cancel_eos_timer( player ); + + __mmplayer_unrealize_streaming_ext(player); + + /* reset */ + player->doing_seek = FALSE; + + /* stop pipeline */ + ret = __gst_stop( player ); + + if ( ret != MM_ERROR_NONE ) + { + debug_error("failed to stop player.\n"); + } + + MMPLAYER_FLEAVE(); + + return ret; +} + +int +_mmplayer_pause(MMHandleType hplayer) // @ +{ + mm_player_t* player = (mm_player_t*)hplayer; + gint64 pos_msec = 0; + gboolean async = FALSE; + gint ret = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + /* check current state */ + MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_PAUSE ); + + /* check pipline building state */ + __mmplayer_check_pipeline(player); + + switch (MMPLAYER_CURRENT_STATE(player)) + { + case MM_PLAYER_STATE_READY: + { + /* check prepare async or not. + * In the case of streaming playback, it's recommned to avoid blocking wait. + */ + mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async); + debug_log("prepare working mode : %s", (async ? "async" : "sync")); + } + break; + + case MM_PLAYER_STATE_PLAYING: + { + /* NOTE : store current point to overcome some bad operation + * ( returning zero when getting current position in paused state) of some + * elements + */ + if ( !gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec)) + debug_warning("getting current position failed in paused\n"); + + player->last_position = pos_msec; + } + break; + } + + /* pause pipeline */ + ret = __gst_pause( player, async ); + + if ( ret != MM_ERROR_NONE ) + { + debug_error("failed to pause player. ret : 0x%x\n", ret); + } + + MMPLAYER_FLEAVE(); + + return ret; +} + +int +_mmplayer_resume(MMHandleType hplayer) +{ + mm_player_t* player = (mm_player_t*)hplayer; + int ret = MM_ERROR_NONE; + gboolean async = FALSE; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + ret = _mmplayer_sound_acquire_focus(&player->sound_focus); + if ( ret != MM_ERROR_NONE ) + { + debug_error("failed to acquire sound focus.\n"); + return ret; + } + + /* check current state */ + MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_RESUME ); + + ret = __gst_resume( player, async ); + + if ( ret != MM_ERROR_NONE ) + { + debug_error("failed to resume player.\n"); + } + + MMPLAYER_FLEAVE(); + + return ret; +} + +int +__mmplayer_set_play_count(mm_player_t* player, gint count) +{ + MMHandleType attrs = 0; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + attrs = MMPLAYER_GET_ATTRS(player); + if ( !attrs ) + { + debug_error("fail to get attributes.\n"); + return MM_ERROR_PLAYER_INTERNAL; + } + + mm_attrs_set_int_by_name(attrs, "profile_play_count", count); + if ( mmf_attrs_commit ( attrs ) ) /* return -1 if error */ + debug_error("failed to commit\n"); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +int +_mmplayer_activate_section_repeat(MMHandleType hplayer, unsigned long start, unsigned long end) +{ + mm_player_t* player = (mm_player_t*)hplayer; + gint64 start_pos = 0; + gint64 end_pos = 0; + gint infinity = -1; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + return_val_if_fail ( end <= GST_TIME_AS_MSECONDS(player->duration), MM_ERROR_INVALID_ARGUMENT ); + + player->section_repeat = TRUE; + player->section_repeat_start = start; + player->section_repeat_end = end; + + start_pos = player->section_repeat_start * G_GINT64_CONSTANT(1000000); + end_pos = player->section_repeat_end * G_GINT64_CONSTANT(1000000); + + __mmplayer_set_play_count( player, infinity ); + + if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, + player->playback_rate, + GST_FORMAT_TIME, + ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ), + GST_SEEK_TYPE_SET, start_pos, + GST_SEEK_TYPE_SET, end_pos))) + { + debug_error("failed to activate section repeat\n"); + + return MM_ERROR_PLAYER_SEEK; + } + + debug_log("succeeded to set section repeat from %d to %d\n", + player->section_repeat_start, player->section_repeat_end); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +static int +__mmplayer_set_pcm_extraction(mm_player_t* player) +{ + gint64 start_nsec = 0; + gint64 end_nsec = 0; + gint64 dur_nsec = 0; + gint64 dur_msec = 0; + int required_start = 0; + int required_end = 0; + int ret = 0; + + MMPLAYER_FENTER(); + + return_val_if_fail( player, FALSE ); + + mm_attrs_multiple_get(player->attrs, + NULL, + "pcm_extraction_start_msec", &required_start, + "pcm_extraction_end_msec", &required_end, + NULL); + + debug_log("pcm extraction required position is from [%d] to [%d] (msec)\n", required_start, required_end); + + if (required_start == 0 && required_end == 0) + { + debug_log("extracting entire stream"); + return MM_ERROR_NONE; + } + else if (required_start < 0 || required_start > required_end || required_end < 0 ) + { + debug_log("invalid range for pcm extraction"); + return MM_ERROR_INVALID_ARGUMENT; + } + + /* get duration */ + ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec); + if ( !ret ) + { + debug_error("failed to get duration"); + return MM_ERROR_PLAYER_INTERNAL; + } + dur_msec = GST_TIME_AS_MSECONDS(dur_nsec); + + if (dur_msec < required_end) // FIXME + { + debug_log("invalid end pos for pcm extraction"); + return MM_ERROR_INVALID_ARGUMENT; + } + + start_nsec = required_start * G_GINT64_CONSTANT(1000000); + end_nsec = required_end * G_GINT64_CONSTANT(1000000); + + if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, + 1.0, + GST_FORMAT_TIME, + ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ), + GST_SEEK_TYPE_SET, start_nsec, + GST_SEEK_TYPE_SET, end_nsec))) + { + debug_error("failed to seek for pcm extraction\n"); + + return MM_ERROR_PLAYER_SEEK; + } + + debug_log("succeeded to set up segment extraction from [%llu] to [%llu] (nsec)\n", start_nsec, end_nsec); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +int +_mmplayer_deactivate_section_repeat(MMHandleType hplayer) +{ + mm_player_t* player = (mm_player_t*)hplayer; + gint64 cur_pos = 0; + gint onetime = 1; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + player->section_repeat = FALSE; + + __mmplayer_set_play_count( player, onetime ); + + gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_pos); + + if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, + 1.0, + GST_FORMAT_TIME, + ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ), + GST_SEEK_TYPE_SET, cur_pos, + GST_SEEK_TYPE_SET, player->duration ))) + { + debug_error("failed to deactivate section repeat\n"); + + return MM_ERROR_PLAYER_SEEK; + } + + MMPLAYER_FENTER(); + + return MM_ERROR_NONE; +} + +int +_mmplayer_set_playspeed(MMHandleType hplayer, float rate) +{ + mm_player_t* player = (mm_player_t*)hplayer; + gint64 pos_msec = 0; + int ret = MM_ERROR_NONE; + int mute = FALSE; + signed long long start = 0, stop = 0; + MMPlayerStateType current_state = MM_PLAYER_STATE_NONE; + MMPLAYER_FENTER(); + + return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED ); + return_val_if_fail ( !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API ); + + /* The sound of video is not supported under 0.0 and over 2.0. */ + if(rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) + { + if (player->can_support_codec & FOUND_PLUGIN_VIDEO) + mute = TRUE; + } + _mmplayer_set_mute(hplayer, mute); + + if (player->playback_rate == rate) + return MM_ERROR_NONE; + + /* If the position is reached at start potion during fast backward, EOS is posted. + * So, This EOS have to be classified with it which is posted at reaching the end of stream. + * */ + player->playback_rate = rate; + + current_state = MMPLAYER_CURRENT_STATE(player); + + if ( current_state != MM_PLAYER_STATE_PAUSED ) + ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec); + + debug_log ("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS (pos_msec), ret, current_state); + + if ( ( current_state == MM_PLAYER_STATE_PAUSED ) + || ( ! ret )) + //|| ( player->last_position != 0 && pos_msec == 0 ) ) + { + debug_warning("returning last point : %lld\n", player->last_position ); + pos_msec = player->last_position; + } + + + if(rate >= 0) + { + start = pos_msec; + stop = GST_CLOCK_TIME_NONE; + } + else + { + start = GST_CLOCK_TIME_NONE; + stop = pos_msec; + } + if ((!gst_element_seek (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, + rate, + GST_FORMAT_TIME, + ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ), + GST_SEEK_TYPE_SET, start, + GST_SEEK_TYPE_SET, stop))) + { + debug_error("failed to set speed playback\n"); + return MM_ERROR_PLAYER_SEEK; + } + + debug_log("succeeded to set speed playback as %0.1f\n", rate); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE;; +} + +int +_mmplayer_set_position(MMHandleType hplayer, int format, int position) // @ +{ + mm_player_t* player = (mm_player_t*)hplayer; + int ret = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + ret = __gst_set_position ( player, format, (unsigned long)position, FALSE ); + + MMPLAYER_FLEAVE(); + + return ret; +} + +int +_mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position) // @ +{ + mm_player_t* player = (mm_player_t*)hplayer; + int ret = MM_ERROR_NONE; + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + ret = __gst_get_position ( player, format, position ); + + return ret; +} + +int +_mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos) // @ +{ + mm_player_t* player = (mm_player_t*)hplayer; + int ret = MM_ERROR_NONE; + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + ret = __gst_get_buffer_position ( player, format, start_pos, stop_pos ); + + return ret; +} + +int +_mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position) // @ +{ + mm_player_t* player = (mm_player_t*)hplayer; + int ret = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + ret = __gst_adjust_subtitle_position(player, format, position); + + MMPLAYER_FLEAVE(); + + return ret; +} +int +_mmplayer_adjust_video_postion(MMHandleType hplayer, int offset) // @ +{ + mm_player_t* player = (mm_player_t*)hplayer; + int ret = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + ret = __gst_adjust_video_position(player, offset); + + MMPLAYER_FLEAVE(); + + return ret; +} + +static gboolean +__mmplayer_is_midi_type( gchar* str_caps) +{ + if ( ( g_strrstr(str_caps, "audio/midi") ) || + ( g_strrstr(str_caps, "application/x-gst_ff-mmf") ) || + ( g_strrstr(str_caps, "application/x-smaf") ) || + ( g_strrstr(str_caps, "audio/x-imelody") ) || + ( g_strrstr(str_caps, "audio/mobile-xmf") ) || + ( g_strrstr(str_caps, "audio/xmf") ) || + ( g_strrstr(str_caps, "audio/mxmf") ) ) + { + debug_log("midi\n"); + + return TRUE; + } + + return FALSE; +} + +static gboolean +__mmplayer_is_only_mp3_type (gchar *str_caps) +{ + if (g_strrstr(str_caps, "application/x-id3") || + (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1"))) + { + return TRUE; + } + return FALSE; +} + +static void +__mmplayer_set_audio_attrs (mm_player_t* player, GstCaps* caps) +{ + GstStructure* caps_structure = NULL; + gint samplerate = 0; + gint channels = 0; + + MMPLAYER_FENTER(); + return_if_fail (player && caps); + + caps_structure = gst_caps_get_structure(caps, 0); + + /* set stream information */ + gst_structure_get_int (caps_structure, "rate", &samplerate); + mm_attrs_set_int_by_name (player->attrs, "content_audio_samplerate", samplerate); + + gst_structure_get_int (caps_structure, "channels", &channels); + mm_attrs_set_int_by_name (player->attrs, "content_audio_channels", channels); + + debug_log ("audio samplerate : %d channels : %d\n", samplerate, channels); +} + +static void +__mmplayer_update_content_type_info(mm_player_t* player) +{ + MMPLAYER_FENTER(); + return_if_fail( player && player->type); + + if (__mmplayer_is_midi_type(player->type)) + { + player->bypass_audio_effect = TRUE; + } + else if (g_strrstr(player->type, "application/x-hls")) + { + /* If it can't know exact type when it parses uri because of redirection case, + * it will be fixed by typefinder or when doing autoplugging. + */ + player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS; + if (player->streamer) + { + player->streamer->is_adaptive_streaming = TRUE; + player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED; + player->streamer->buffering_req.runtime_second = 5; + } + } + else if (g_strrstr(player->type, "application/dash+xml")) + { + player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH; + } + + MMPLAYER_FLEAVE(); +} + +static void +__mmplayer_typefind_have_type( GstElement *tf, guint probability, // @ +GstCaps *caps, gpointer data) +{ + mm_player_t* player = (mm_player_t*)data; + GstPad* pad = NULL; + + MMPLAYER_FENTER(); + + return_if_fail( player && tf && caps ); + + /* store type string */ + MMPLAYER_FREEIF(player->type); + player->type = gst_caps_to_string(caps); + if (player->type) + debug_log("meida type %s found, probability %d%% / %d\n", player->type, probability, gst_caps_get_size(caps)); + + if ( (!MMPLAYER_IS_WFD_STREAMING( player )) && + (!MMPLAYER_IS_RTSP_STREAMING( player )) && + (g_strrstr(player->type, "audio/x-raw-int"))) + { + debug_error("not support media format\n"); + + if (player->msg_posted == FALSE) + { + MMMessageParamType msg_param; + memset (&msg_param, 0, sizeof(MMMessageParamType)); + + msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT; + MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param ); + + /* don't post more if one was sent already */ + player->msg_posted = TRUE; + } + return; + } + + __mmplayer_update_content_type_info(player); + + pad = gst_element_get_static_pad(tf, "src"); + if ( !pad ) + { + debug_error("fail to get typefind src pad.\n"); + return; + } + + if (player->use_decodebin) + { + if(!__mmplayer_try_to_plug_decodebin( player, pad, caps )) + { + gboolean async = FALSE; + debug_error("failed to autoplug %s\n", player->type); + + mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async); + + if ( async && player->msg_posted == FALSE ) + { + __mmplayer_handle_missed_plugin( player ); + } + + goto DONE; + } + } + else + { + /* try to plug */ + if ( ! __mmplayer_try_to_plug( player, pad, caps ) ) + { + gboolean async = FALSE; + debug_error("failed to autoplug %s\n", player->type); + + mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async); + + if ( async && player->msg_posted == FALSE ) + { + __mmplayer_handle_missed_plugin( player ); + } + + goto DONE; + } + + /* finish autopluging if no dynamic pad waiting */ + if( ( ! player->have_dynamic_pad) && ( ! player->has_many_types) ) + { + if ( ! MMPLAYER_IS_RTSP_STREAMING( player ) ) + { + __mmplayer_pipeline_complete( NULL, (gpointer)player ); + } + } + } + +DONE: + gst_object_unref( GST_OBJECT(pad) ); + + MMPLAYER_FLEAVE(); + + return; +} + +#ifdef _MM_PLAYER_ALP_PARSER +void check_name (void *data, void *user_data) +{ + mm_player_t* player = user_data; + + if (g_strrstr((gchar*)data, "mpegaudioparse")) + { + debug_log("mpegaudioparse - set alp-mp3dec\n"); + g_object_set(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "alp-mp3dec", TRUE, NULL); + } +} +#endif + +static GstElement * +__mmplayer_create_decodebin (mm_player_t* player) +{ + GstElement *decodebin = NULL; + + MMPLAYER_FENTER(); + + /* create decodebin */ + decodebin = gst_element_factory_make("decodebin", NULL); + + if (!decodebin) + { + debug_error("fail to create decodebin\n"); + goto ERROR; + } + + /* raw pad handling signal */ + MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", + G_CALLBACK(__mmplayer_gst_decode_pad_added), player); + + /* no-more-pad pad handling signal */ + MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", + G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player); + + MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", + G_CALLBACK(__mmplayer_gst_decode_pad_removed), player); + + /* This signal is emitted when a pad for which there is no further possible + decoding is added to the decodebin.*/ + MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type", + G_CALLBACK(__mmplayer_gst_decode_unknown_type), player ); + + /* This signal is emitted whenever decodebin finds a new stream. It is emitted + before looking for any elements that can handle that stream.*/ + MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue", + G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player); + + /* This signal is emitted whenever decodebin finds a new stream. It is emitted + before looking for any elements that can handle that stream.*/ + MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", + G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player); + + /* This signal is emitted once decodebin has finished decoding all the data.*/ + MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained", + G_CALLBACK(__mmplayer_gst_decode_drained), player); + + /* This signal is emitted when a element is added to the bin.*/ + MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added", + G_CALLBACK(__mmplayer_gst_element_added), player); + +ERROR: + return decodebin; +} + +static gboolean +__mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps) +{ + MMPlayerGstElement* mainbin = NULL; + GstElement* decodebin = NULL; + GstElement* queue2 = NULL; + GstPad* sinkpad = NULL; + GstPad* qsrcpad= NULL; + gchar *caps_str = NULL; + gint64 dur_bytes = 0L; + gchar* file_buffering_path = NULL; + gboolean use_file_buffer = FALSE; + + guint max_buffer_size_bytes = 0; + gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second; + + MMPLAYER_FENTER(); + return_val_if_fail (player && player->pipeline && player->pipeline->mainbin, FALSE); + + mainbin = player->pipeline->mainbin; + + if ((!MMPLAYER_IS_HTTP_PD(player)) && + (MMPLAYER_IS_HTTP_STREAMING(player))) + { + debug_log ("creating http streaming buffering queue (queue2)\n"); + + if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) + { + debug_error ("MMPLAYER_M_MUXED_S_BUFFER is not null\n"); + } + else + { + queue2 = gst_element_factory_make ("queue2", "queue2"); + if (!queue2) + { + debug_error ("failed to create buffering queue element\n"); + goto ERROR; + } + + if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) + { + debug_error("failed to add buffering queue\n"); + goto ERROR; + } + + sinkpad = gst_element_get_static_pad(queue2, "sink"); + qsrcpad = gst_element_get_static_pad(queue2, "src"); + + if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) + { + debug_error("failed to link buffering queue\n"); + goto ERROR; + } + + // if ( !MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) + { + if ( !gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes)) + debug_error("fail to get duration.\n"); + + debug_log("dur_bytes = %lld\n", dur_bytes); + + if (dur_bytes > 0) + { + use_file_buffer = MMPLAYER_USE_FILE_FOR_BUFFERING(player); + file_buffering_path = g_strdup(player->ini.http_file_buffer_path); + } + else + { + dur_bytes = 0; + } + } + + /* NOTE : we cannot get any duration info from ts container in case of streaming */ + // if(!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux")) + if(!g_strrstr(player->type, "video/mpegts")) + { + max_buffer_size_bytes = (use_file_buffer)?(player->ini.http_max_size_bytes):(5*1024*1024); + debug_log("max_buffer_size_bytes = %d\n", max_buffer_size_bytes); + + __mm_player_streaming_set_queue2(player->streamer, + queue2, + FALSE, + max_buffer_size_bytes, + player->ini.http_buffering_time, + 1.0, // no meaning + player->ini.http_buffering_limit, // no meaning + use_file_buffer, + file_buffering_path, + (guint64)dur_bytes); + } + + MMPLAYER_FREEIF(file_buffering_path); + if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent (queue2)) + { + debug_error("failed to sync queue2 state with parent\n"); + goto ERROR; + } + + srcpad = qsrcpad; + + gst_object_unref(GST_OBJECT(sinkpad)); + + mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER; + mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2; + } + } + + /* create decodebin */ + decodebin = __mmplayer_create_decodebin(player); + + if (!decodebin) + { + debug_error("can not create autoplug element\n"); + goto ERROR; + } + + if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) + { + debug_error("failed to add decodebin\n"); + goto ERROR; + } + + /* to force caps on the decodebin element and avoid reparsing stuff by + * typefind. It also avoids a deadlock in the way typefind activates pads in + * the state change */ + g_object_set (decodebin, "sink-caps", caps, NULL); + + sinkpad = gst_element_get_static_pad(decodebin, "sink"); + + if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) + { + debug_error("failed to link decodebin\n"); + goto ERROR; + } + + gst_object_unref(GST_OBJECT(sinkpad)); + + mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG; + mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin; + + /* set decodebin property about buffer in streaming playback. * + * in case of hls, it does not need to have big buffer * + * because it is kind of adaptive streaming. */ + if ( ((!MMPLAYER_IS_HTTP_PD(player)) && + (MMPLAYER_IS_HTTP_STREAMING(player))) || MMPLAYER_IS_DASH_STREAMING (player)) + { + guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES; + guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME; + init_buffering_time = (init_buffering_time != 0)?(init_buffering_time):(player->ini.http_buffering_time); + + if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) { + max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES; + max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME; + } + + g_object_set (G_OBJECT(decodebin), "use-buffering", TRUE, + "high-percent", (gint)player->ini.http_buffering_limit, + "low-percent", 1, // 1% + "max-size-bytes", max_size_bytes, + "max-size-time", (guint64)(max_size_time * GST_SECOND), + "max-size-buffers", 0, NULL); // disable or automatic + } + + if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) + { + debug_error("failed to sync decodebin state with parent\n"); + goto ERROR; + } + + MMPLAYER_FLEAVE(); + + return TRUE; + +ERROR: + + MMPLAYER_FREEIF( caps_str ); + + if (sinkpad) + gst_object_unref(GST_OBJECT(sinkpad)); + + if (queue2) + { + /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state. + * You need to explicitly set elements to the NULL state before + * dropping the final reference, to allow them to clean up. + */ + gst_element_set_state(queue2, GST_STATE_NULL); + + /* And, it still has a parent "player". + * You need to let the parent manage the object instead of unreffing the object directly. + */ + gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2); + gst_object_unref (queue2); + queue2 = NULL; + } + + if (decodebin) + { + /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state. + * You need to explicitly set elements to the NULL state before + * dropping the final reference, to allow them to clean up. + */ + gst_element_set_state(decodebin, GST_STATE_NULL); + + /* And, it still has a parent "player". + * You need to let the parent manage the object instead of unreffing the object directly. + */ + + gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin); + gst_object_unref (decodebin); + decodebin = NULL; + } + + return FALSE; +} + +/* it will return first created element */ +static gboolean +__mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps) // @ +{ + MMPlayerGstElement* mainbin = NULL; + const char* mime = NULL; + const GList* item = NULL; + const gchar* klass = NULL; + GstCaps* res = NULL; + gboolean skip = FALSE; + GstPad* queue_pad = NULL; + GstElement* queue = NULL; + GstElement *element = NULL; + + MMPLAYER_FENTER(); + + return_val_if_fail( player && player->pipeline && player->pipeline->mainbin, FALSE ); + + mainbin = player->pipeline->mainbin; + + mime = gst_structure_get_name(gst_caps_get_structure(caps, 0)); + + /* return if we got raw output */ + if(g_str_has_prefix(mime, "video/x-raw") || g_str_has_prefix(mime, "audio/x-raw") + || g_str_has_prefix(mime, "text/plain") ||g_str_has_prefix(mime, "text/x-pango-markup")) + { + + element = (GstElement*)gst_pad_get_parent(pad); +/* NOTE : When no decoder has added during autoplugging. like a simple wave playback. + * No queue will be added. I think it can caused breaking sound when playing raw audio + * frames but there's no different. Decodebin also doesn't add with those wav fils. + * Anyway, currentely raw-queue seems not necessary. + */ +#if 1 + /* NOTE : check if previously linked element is demuxer/depayloader/parse means no decoder + * has linked. if so, we need to add queue for quality of output. note that + * decodebin also has same problem. + */ + klass = gst_element_factory_get_metadata (gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS); + + /* add queue if needed */ + if( (g_strrstr(klass, "Demux") || g_strrstr(klass, "Depayloader") + || g_strrstr(klass, "Parse")) && !g_str_has_prefix(mime, "text")) + { + debug_log("adding raw queue\n"); + + queue = gst_element_factory_make("queue", NULL); + if ( ! queue ) + { + debug_warning("failed to create queue\n"); + goto ERROR; + } + + /* warmup */ + if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY) ) + { + debug_warning("failed to set state READY to queue\n"); + goto ERROR; + } + + /* add to pipeline */ + if ( ! gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue) ) + { + debug_warning("failed to add queue\n"); + goto ERROR; + } + + /* link queue */ + queue_pad = gst_element_get_static_pad(queue, "sink"); + + if ( GST_PAD_LINK_OK != gst_pad_link(pad, queue_pad) ) + { + debug_warning("failed to link queue\n"); + goto ERROR; + } + gst_object_unref ( GST_OBJECT(queue_pad) ); + queue_pad = NULL; + + /* running */ + if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED) ) + { + debug_warning("failed to set state PAUSED to queue\n"); + goto ERROR; + } + + /* replace given pad to queue:src */ + pad = gst_element_get_static_pad(queue, "src"); + if ( ! pad ) + { + debug_warning("failed to get pad from queue\n"); + goto ERROR; + } + } +#endif + /* check if player can do start continually */ + MMPLAYER_CHECK_CMD_IF_EXIT(player); + + if(__mmplayer_link_sink(player,pad)) + __mmplayer_gst_decode_callback(element, pad, player); + + gst_object_unref( GST_OBJECT(element)); + element = NULL; + + return TRUE; + } + + item = player->factories; + for(; item != NULL ; item = item->next) + { + GstElementFactory *factory = GST_ELEMENT_FACTORY(item->data); + const GList *pads; + gint idx = 0; + + skip = FALSE; + + /* filtering exclude keyword */ + for ( idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++ ) + { + if ( g_strrstr(GST_OBJECT_NAME (factory), + player->ini.exclude_element_keyword[idx] ) ) + { + debug_warning("skipping [%s] by exculde keyword [%s]\n", + GST_OBJECT_NAME (factory), + player->ini.exclude_element_keyword[idx] ); + + skip = TRUE; + break; + } + } + + if ( MMPLAYER_IS_RTSP_STREAMING(player) && g_strrstr(GST_OBJECT_NAME (factory), "omx_mpeg4dec")) + { + // omx decoder can not support mpeg4video data partitioned + // rtsp streaming didn't know mpeg4video data partitioned format + // so, if rtsp playback, player will skip omx_mpeg4dec. + debug_warning("skipping [%s] when rtsp streaming \n", + GST_OBJECT_NAME (factory)); + + skip = TRUE; + } + + if ( skip ) continue; + + /* check factory class for filtering */ + klass = gst_element_factory_get_metadata (GST_ELEMENT_FACTORY(factory), GST_ELEMENT_METADATA_KLASS); + + /*parsers are not required in case of external feeder*/ + if (g_strrstr(klass, "Codec/Parser") && MMPLAYER_IS_ES_BUFF_SRC(player)) + continue; + + /* NOTE : msl don't need to use image plugins. + * So, those plugins should be skipped for error handling. + */ + if ( g_strrstr(klass, "Codec/Decoder/Image") ) + { + debug_log("skipping [%s] by not required\n", GST_OBJECT_NAME (factory)); + continue; + } + + /* check pad compatability */ + for(pads = gst_element_factory_get_static_pad_templates(factory); + pads != NULL; pads=pads->next) + { + GstStaticPadTemplate *temp1 = pads->data; + GstCaps* static_caps = NULL; + + if( temp1->direction != GST_PAD_SINK + || temp1->presence != GST_PAD_ALWAYS) + continue; + + if ( GST_IS_CAPS( &temp1->static_caps.caps) ) + { + /* using existing caps */ + static_caps = gst_caps_ref(temp1->static_caps.caps ); + } + else + { + /* create one */ + static_caps = gst_caps_from_string ( temp1->static_caps.string ); + } + + res = gst_caps_intersect((GstCaps*)caps, static_caps); + gst_caps_unref( static_caps ); + static_caps = NULL; + + if( res && !gst_caps_is_empty(res) ) + { + GstElement *new_element; + GList *elements = player->parsers; + char *name_template = g_strdup(temp1->name_template); + gchar *name_to_plug = GST_OBJECT_NAME(factory); + gst_caps_unref(res); + + /* check ALP Codec can be used or not */ + if ((g_strrstr(klass, "Codec/Decoder/Audio"))) + { + /* consider mp3 audio only */ + if ( !MMPLAYER_IS_STREAMING(player) && __mmplayer_is_only_mp3_type(player->type) ) + { + /* try to use ALP decoder first instead of selected decoder */ + GstElement *element = NULL; + GstElementFactory * element_facory; + gchar *path = NULL; + guint64 data_size = 0; + #define MIN_THRESHOLD_SIZE 320 * 1024 // 320K + struct stat sb; + + mm_attrs_get_string_by_name(player->attrs, "profile_uri", &path); + + if (stat(path, &sb) == 0) + { + data_size = (guint64)sb.st_size; + } + debug_log("file size : %u", data_size); + + if (data_size > MIN_THRESHOLD_SIZE) + { + debug_log("checking if ALP can be used or not"); + element = gst_element_factory_make("omx_mp3dec", "omx mp3 decoder"); + if ( element ) + { + /* check availability because multi-instance is not supported */ + GstStateChangeReturn ret = gst_element_set_state(element, GST_STATE_READY); + + if (ret != GST_STATE_CHANGE_SUCCESS) // use just selected decoder + { + gst_object_unref (element); + } + else if (ret == GST_STATE_CHANGE_SUCCESS) // replace facotry to use omx + { + /* clean */ + gst_element_set_state(element, GST_STATE_NULL); + gst_object_unref (element); + + element_facory = gst_element_factory_find("omx_mp3dec"); + /* replace, otherwise use selected thing instead */ + if (element_facory) + { + factory = element_facory; + name_to_plug = GST_OBJECT_NAME(factory); + } + + /* make parser alp mode */ + #ifdef _MM_PLAYER_ALP_PARSER + g_list_foreach (player->parsers, check_name, player); + #endif + } + } + } + } + } + else if ((g_strrstr(klass, "Codec/Decoder/Video"))) + { + if ( g_strrstr(GST_OBJECT_NAME(factory), "omx_") ) + { + char *env = getenv ("MM_PLAYER_HW_CODEC_DISABLE"); + if (env != NULL) + { + if (strncasecmp(env, "yes", 3) == 0) + { + debug_log("skipping [%s] by disabled\n", name_to_plug); + MMPLAYER_FREEIF(name_template); + continue; + } + } + } + } + + debug_log("found %s to plug\n", name_to_plug); + + new_element = gst_element_factory_create(GST_ELEMENT_FACTORY(factory), NULL); + if ( ! new_element ) + { + debug_error("failed to create element [%s]. continue with next.\n", + GST_OBJECT_NAME (factory)); + + MMPLAYER_FREEIF(name_template); + + continue; + } + + /* check and skip it if it was already used. Otherwise, it can be an infinite loop + * because parser can accept its own output as input. + */ + if (g_strrstr(klass, "Parser")) + { + gchar *selected = NULL; + + for ( ; elements; elements = g_list_next(elements)) + { + gchar *element_name = elements->data; + + if (g_strrstr(element_name, name_to_plug)) + { + debug_log("but, %s already linked, so skipping it\n", name_to_plug); + skip = TRUE; + } + } + + if (skip) + { + MMPLAYER_FREEIF(name_template); + continue; + } + + selected = g_strdup(name_to_plug); + player->parsers = g_list_append(player->parsers, selected); + } + + /* store specific handles for futher control */ + if(g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) + { + /* FIXIT : first value will be overwritten if there's more + * than 1 demuxer/parser + */ + debug_log("plugged element is demuxer. take it\n"); + mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX; + mainbin[MMPLAYER_M_DEMUX].gst = new_element; + + /*Added for multi audio support */ + if(g_strrstr(klass, "Demux")) + { + mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX; + mainbin[MMPLAYER_M_DEMUX_EX].gst = new_element; + + /* NOTE : workaround for bug in mpegtsdemux since doesn't emit + no-more-pad signal. this may cause wrong content attributes at PAUSED state + this code should be removed after mpegtsdemux is fixed */ + if ( g_strrstr(GST_OBJECT_NAME(factory), "mpegtsdemux") ) + { + debug_warning("force no-more-pad to TRUE since mpegtsdemux os not giving no-more-pad signal. content attributes may wrong"); + player->no_more_pad = TRUE; + } + } + if (g_strrstr(name_to_plug, "asfdemux")) // to support trust-zone only + { + g_object_set(mainbin[MMPLAYER_M_DEMUX_EX].gst, "file-location", player->profile.uri,NULL); + } + } + else if(g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player,pad)) + { + if(mainbin[MMPLAYER_M_DEC1].gst == NULL) + { + debug_log("plugged element is decoder. take it[MMPLAYER_M_DEC1]\n"); + mainbin[MMPLAYER_M_DEC1].id = MMPLAYER_M_DEC1; + mainbin[MMPLAYER_M_DEC1].gst = new_element; + } + else if(mainbin[MMPLAYER_M_DEC2].gst == NULL) + { + debug_log("plugged element is decoder. take it[MMPLAYER_M_DEC2]\n"); + mainbin[MMPLAYER_M_DEC2].id = MMPLAYER_M_DEC2; + mainbin[MMPLAYER_M_DEC2].gst = new_element; + } + /* NOTE : IF one codec is found, add it to supported_codec and remove from + * missing plugin. Both of them are used to check what's supported codec + * before returning result of play start. And, missing plugin should be + * updated here for multi track files. + */ + if(g_str_has_prefix(mime, "video")) + { + GstPad *src_pad = NULL; + GstPadTemplate *pad_templ = NULL; + GstCaps *caps = NULL; + gchar *caps_str = NULL; + + debug_log("found VIDEO decoder\n"); + player->not_supported_codec &= MISSING_PLUGIN_AUDIO; + player->can_support_codec |= FOUND_PLUGIN_VIDEO; + + src_pad = gst_element_get_static_pad (new_element, "src"); + pad_templ = gst_pad_get_pad_template (src_pad); + caps = GST_PAD_TEMPLATE_CAPS(pad_templ); + + caps_str = gst_caps_to_string(caps); + + /* clean */ + MMPLAYER_FREEIF( caps_str ); + gst_object_unref (src_pad); + } + else if (g_str_has_prefix(mime, "audio")) + { + debug_log("found AUDIO decoder\n"); + player->not_supported_codec &= MISSING_PLUGIN_VIDEO; + player->can_support_codec |= FOUND_PLUGIN_AUDIO; + } + } + + if ( ! __mmplayer_close_link(player, pad, new_element, + name_template,gst_element_factory_get_static_pad_templates(factory)) ) + { + MMPLAYER_FREEIF(name_template); + if (player->keep_detecting_vcodec) + continue; + + /* Link is failed even though a supportable codec is found. */ + __mmplayer_check_not_supported_codec(player, klass, mime); + + debug_error("failed to call _close_link\n"); + return FALSE; + } + + MMPLAYER_FREEIF(name_template); + return TRUE; + } + + gst_caps_unref(res); + break; + } + } + + /* There is no available codec. */ + __mmplayer_check_not_supported_codec(player, klass, mime); + + MMPLAYER_FLEAVE(); + return FALSE; + +ERROR: + /* release */ + if ( queue ) + gst_object_unref( queue ); + + if ( queue_pad ) + gst_object_unref( queue_pad ); + + if ( element ) + gst_object_unref ( element ); + + return FALSE; +} + + +static int +__mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime) +{ + MMPLAYER_FENTER(); + + return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail ( mime, MM_ERROR_INVALID_ARGUMENT ); + + debug_log("class : %s, mime : %s \n", factory_class, mime ); + + /* add missing plugin */ + /* NOTE : msl should check missing plugin for image mime type. + * Some motion jpeg clips can have playable audio track. + * So, msl have to play audio after displaying popup written video format not supported. + */ + if ( !( player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst ) ) + { + if ( !( player->can_support_codec | player->videodec_linked | player->audiodec_linked ) ) + { + debug_log("not found demuxer\n"); + player->not_found_demuxer = TRUE; + player->unlinked_demuxer_mime = g_strdup_printf ( "%s", mime ); + + goto DONE; + } + } + + if( !g_strrstr(factory_class, "Demuxer")) + { + if( ( g_str_has_prefix(mime, "video") ) ||( g_str_has_prefix(mime, "image") ) ) + { + debug_log("can support codec=%d, vdec_linked=%d, adec_linked=%d\n", + player->can_support_codec, player->videodec_linked, player->audiodec_linked); + + /* check that clip have multi tracks or not */ + if ( ( player->can_support_codec & FOUND_PLUGIN_VIDEO ) && ( player->videodec_linked ) ) + { + debug_log("video plugin is already linked\n"); + } + else + { + debug_warning("add VIDEO to missing plugin\n"); + player->not_supported_codec |= MISSING_PLUGIN_VIDEO; + } + } + else if ( g_str_has_prefix(mime, "audio") ) + { + if ( ( player->can_support_codec & FOUND_PLUGIN_AUDIO ) && ( player->audiodec_linked ) ) + { + debug_log("audio plugin is already linked\n"); + } + else + { + debug_warning("add AUDIO to missing plugin\n"); + player->not_supported_codec |= MISSING_PLUGIN_AUDIO; + } + } + } + +DONE: + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + + +static void +__mmplayer_pipeline_complete(GstElement *decodebin, gpointer data) +{ + mm_player_t* player = (mm_player_t*)data; + + MMPLAYER_FENTER(); + + return_if_fail( player ); + + /* remove fakesink. */ + if ( !__mmplayer_gst_remove_fakesink( player, + &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]) ) + { + /* NOTE : __mmplayer_pipeline_complete() can be called several time. because + * signaling mechanism ( pad-added, no-more-pad, new-decoded-pad ) from various + * source element are not same. To overcome this situation, this function will called + * several places and several times. Therefore, this is not an error case. + */ + return; + } + + debug_log("pipeline has completely constructed\n"); + + if (( player->ini.async_start ) && + ( player->msg_posted == FALSE ) && + ( player->cmd >= MMPLAYER_COMMAND_START )) + { + __mmplayer_handle_missed_plugin( player ); + } + + MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-complete" ); +} + +static gboolean +__mmplayer_verify_next_play_path(mm_player_t *player) +{ + MMHandleType attrs = 0; + MMPlayerParseProfile profile; + gint uri_idx = 0, check_cnt = 0; + char *uri = NULL; + gint mode = MM_PLAYER_PD_MODE_NONE; + gint count = 0; + guint num_of_list = 0; + + MMPLAYER_FENTER(); + + debug_log("checking for gapless play"); + + if (player->pipeline->textbin) + { + debug_error("subtitle path is enabled. gapless play is not supported.\n"); + goto ERROR; + } + + attrs = MMPLAYER_GET_ATTRS(player); + if ( !attrs ) + { + debug_error("fail to get attributes.\n"); + goto ERROR; + } + + /* seamless playback is supported in case of audio only */ + mm_attrs_get_int_by_name(attrs, "content_video_found", &mode); + if (mode) + { + debug_log("video found"); + goto ERROR; + } + + if (mm_attrs_get_int_by_name (attrs, "pd_mode", &mode) == MM_ERROR_NONE) + { + if (mode == TRUE) + { + debug_warning("pd mode\n"); + goto ERROR; + } + } + + if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE) + { + debug_error("can not get play count\n"); + } + + num_of_list = g_list_length(player->uri_info.uri_list); + + debug_log("repeat count = %d, num_of_list = %d\n", count, num_of_list); + + if ( num_of_list == 0 ) + { + if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) + { + debug_error("can not get profile_uri\n"); + goto ERROR; + } + + if (!uri) + { + debug_error("uri list is empty.\n"); + goto ERROR; + } + + player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri)); + debug_log("add original path : %s ", uri); + + num_of_list = 1; + uri= NULL; + } + + uri_idx = player->uri_info.uri_idx; + + while(TRUE) + { + check_cnt++; + + if (check_cnt > num_of_list) + { + debug_error("there is no valid uri."); + goto ERROR; + } + + debug_log("uri idx : %d / %d\n", uri_idx, num_of_list); + + if ( uri_idx < num_of_list-1 ) + { + uri_idx++; + } + else + { + if ((count <= 1) && (count != -1)) + { + debug_log("no repeat."); + goto ERROR; + } + else if ( count > 1 ) /* decrease play count */ + { + /* we successeded to rewind. update play count and then wait for next EOS */ + count--; + + mm_attrs_set_int_by_name(attrs, "profile_play_count", count); + + /* commit attribute */ + if ( mmf_attrs_commit ( attrs ) ) + { + debug_error("failed to commit attribute\n"); + } + } + + /* count < 0 : repeat continually */ + uri_idx = 0; + } + + uri = g_list_nth_data(player->uri_info.uri_list, uri_idx); + debug_log("uri idx : %d, uri = %s\n", uri_idx, uri); + + if (uri == NULL) + { + debug_warning("next uri does not exist\n"); + continue; + } + + if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) + { + debug_error("failed to parse profile\n"); + continue; + } + + if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) && + (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) + { + debug_warning("uri type is not supported (%d).", profile.uri_type); + continue; + } + + break; + } + + player->uri_info.uri_idx = uri_idx; + mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri); + + + if (mmf_attrs_commit(player->attrs)) + { + debug_error("failed to commit.\n"); + goto ERROR; + } + + debug_log("next uri %s (%d)\n", uri, uri_idx); + + return TRUE; + +ERROR: + + debug_error("unable to play next path. EOS will be posted soon.\n"); + return FALSE; +} + +static void +__mmplayer_initialize_next_play(mm_player_t *player) +{ + int i; + + MMPLAYER_FENTER(); + + player->smooth_streaming = FALSE; + player->videodec_linked = 0; + player->audiodec_linked = 0; + player->videosink_linked = 0; + player->audiosink_linked = 0; + player->textsink_linked = 0; + player->is_external_subtitle_present = FALSE; + player->not_supported_codec = MISSING_PLUGIN_NONE; + player->can_support_codec = FOUND_PLUGIN_NONE; + player->pending_seek.is_pending = FALSE; + player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME; + player->pending_seek.pos = 0; + player->msg_posted = FALSE; + player->has_many_types = FALSE; + player->no_more_pad = FALSE; + player->is_drm_file = FALSE; + player->not_found_demuxer = 0; + player->doing_seek = FALSE; + player->max_audio_channels = 0; + player->is_subtitle_force_drop = FALSE; + player->play_subtitle = FALSE; + player->use_textoverlay = FALSE; + player->adjust_subtitle_pos = 0; + + player->updated_bitrate_count = 0; + player->total_bitrate = 0; + player->updated_maximum_bitrate_count = 0; + player->total_maximum_bitrate = 0; + + _mmplayer_track_initialize(player); + + for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) + { + player->bitrate[i] = 0; + player->maximum_bitrate[i] = 0; + } + + if (player->v_stream_caps) + { + gst_caps_unref(player->v_stream_caps); + player->v_stream_caps = NULL; + } + + mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0); + mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0); + + /* clean found parsers */ + if (player->parsers) + { + GList *parsers = player->parsers; + for ( ;parsers ; parsers = g_list_next(parsers)) + { + gchar *name = parsers->data; + MMPLAYER_FREEIF(name); + } + g_list_free(player->parsers); + player->parsers = NULL; + } + + /* clean found audio decoders */ + if (player->audio_decoders) + { + GList *a_dec = player->audio_decoders; + for ( ;a_dec ; a_dec = g_list_next(a_dec)) + { + gchar *name = a_dec->data; + MMPLAYER_FREEIF(name); + } + g_list_free(player->audio_decoders); + player->audio_decoders = NULL; + } + + MMPLAYER_FLEAVE(); +} + +static void +__mmplayer_activate_next_source(mm_player_t *player, GstState target) +{ + MMPlayerGstElement *mainbin = NULL; + MMMessageParamType msg_param = {0,}; + GstElement *element = NULL; + MMHandleType attrs = 0; + char *uri = NULL; + enum MainElementID elemId = MMPLAYER_M_NUM; + + MMPLAYER_FENTER(); + + if ((player == NULL) || + (player->pipeline == NULL) || + (player->pipeline->mainbin == NULL)) + { + debug_error("player is null.\n"); + goto ERROR; + } + + mainbin = player->pipeline->mainbin; + msg_param.code = MM_ERROR_PLAYER_INTERNAL; + + attrs = MMPLAYER_GET_ATTRS(player); + if ( !attrs ) + { + debug_error("fail to get attributes.\n"); + goto ERROR; + } + + /* Initialize Player values */ + __mmplayer_initialize_next_play(player); + + mm_attrs_get_string_by_name(attrs, "profile_uri", &uri); + + if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) + { + debug_error("failed to parse profile\n"); + msg_param.code = MM_ERROR_PLAYER_INVALID_URI; + goto ERROR; + } + + if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) || + (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) + { + debug_error("it's dash or hls. not support."); + msg_param.code = MM_ERROR_PLAYER_INVALID_URI; + goto ERROR; + } + + /* setup source */ + switch ( player->profile.uri_type ) + { + /* file source */ + case MM_PLAYER_URI_TYPE_FILE: + { + debug_log("using filesrc for 'file://' handler.\n"); + + element = gst_element_factory_make("filesrc", "source"); + + if ( !element ) + { + debug_error("failed to create filesrc\n"); + break; + } + + g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */ + break; + } + case MM_PLAYER_URI_TYPE_URL_HTTP: + { + gchar *user_agent, *proxy, *cookies, **cookie_list; + gint http_timeout = DEFAULT_HTTP_TIMEOUT; + user_agent = proxy = cookies = NULL; + cookie_list = NULL; + + element = gst_element_factory_make(player->ini.name_of_httpsrc, "http_streaming_source"); + if ( !element ) + { + debug_error("failed to create http streaming source element[%s].\n", player->ini.name_of_httpsrc); + break; + } + debug_log("using http streamming source [%s].\n", player->ini.name_of_httpsrc); + + /* get attribute */ + mm_attrs_get_string_by_name ( attrs, "streaming_cookie", &cookies ); + mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent ); + mm_attrs_get_string_by_name ( attrs, "streaming_proxy", &proxy ); + mm_attrs_get_int_by_name ( attrs, "streaming_timeout", &http_timeout ); + + if ((http_timeout == DEFAULT_HTTP_TIMEOUT) && + (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) + { + debug_log("get timeout from ini\n"); + http_timeout = player->ini.http_timeout; + } + + /* get attribute */ + secure_debug_log("location : %s\n", player->profile.uri); + secure_debug_log("cookies : %s\n", cookies); + secure_debug_log("proxy : %s\n", proxy); + secure_debug_log("user_agent : %s\n", user_agent); + debug_log("timeout : %d\n", http_timeout); + + /* setting property to streaming source */ + g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL); + g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL); + g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL); + + /* check if prosy is vailid or not */ + if ( util_check_valid_url ( proxy ) ) + g_object_set(G_OBJECT(element), "proxy", proxy, NULL); + /* parsing cookies */ + if ( ( cookie_list = util_get_cookie_list ((const char*)cookies) ) ) + g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL); + if ( user_agent ) + g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL); + break; + } + default: + debug_error("not support uri type %d\n", player->profile.uri_type); + break; + } + + if ( !element ) + { + debug_error("no source element was created.\n"); + goto ERROR; + } + + if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) + { + debug_error("failed to add source element to pipeline\n"); + gst_object_unref(GST_OBJECT(element)); + element = NULL; + goto ERROR; + } + + /* take source element */ + mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC; + mainbin[MMPLAYER_M_SRC].gst = element; + + element = NULL; + + if (MMPLAYER_IS_HTTP_STREAMING(player)) + { + if (player->streamer == NULL) + { + player->streamer = __mm_player_streaming_create(); + __mm_player_streaming_initialize(player->streamer); + } + + elemId = MMPLAYER_M_TYPEFIND; + element = gst_element_factory_make("typefind", "typefinder"); + MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", + G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player ); + } + else + { + elemId = MMPLAYER_M_AUTOPLUG; + element = __mmplayer_create_decodebin(player); + } + + /* check autoplug element is OK */ + if ( ! element ) + { + debug_error("can not create element (%d)\n", elemId); + goto ERROR; + } + + if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) + { + debug_error("failed to add sinkbin to pipeline\n"); + gst_object_unref(GST_OBJECT(element)); + element = NULL; + goto ERROR; + } + + mainbin[elemId].id = elemId; + mainbin[elemId].gst = element; + + if ( gst_element_link (mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE ) + { + debug_error("Failed to link src - autoplug (or typefind)\n"); + goto ERROR; + } + + if (gst_element_set_state (mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) + { + debug_error("Failed to change state of src element\n"); + goto ERROR; + } + + if (!MMPLAYER_IS_HTTP_STREAMING(player)) + { + if (gst_element_set_state (mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) + { + debug_error("Failed to change state of decodebin\n"); + goto ERROR; + } + } + else + { + if (gst_element_set_state (mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) + { + debug_error("Failed to change state of src element\n"); + goto ERROR; + } + } + + player->gapless.stream_changed = TRUE; + player->gapless.running = TRUE; + MMPLAYER_FLEAVE(); + return; + +ERROR: + MMPLAYER_PLAYBACK_UNLOCK(player); + + if (!player->msg_posted) + { + MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param); + player->msg_posted = TRUE; + } + return; +} + +static gboolean +__mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type) +{ + mm_player_selector_t *selector = &player->selector[type]; + MMPlayerGstElement *sinkbin = NULL; + enum MainElementID selectorId = MMPLAYER_M_NUM; + enum MainElementID sinkId = MMPLAYER_M_NUM; + GstPad *srcpad = NULL; + GstPad *sinkpad = NULL; + + MMPLAYER_FENTER(); + return_val_if_fail (player, FALSE); + + debug_log("type %d", type); + + switch (type) + { + case MM_PLAYER_TRACK_TYPE_AUDIO: + selectorId = MMPLAYER_M_A_INPUT_SELECTOR; + sinkId = MMPLAYER_A_BIN; + sinkbin = player->pipeline->audiobin; + break; + case MM_PLAYER_TRACK_TYPE_TEXT: + selectorId = MMPLAYER_M_T_INPUT_SELECTOR; + sinkId = MMPLAYER_T_BIN; + sinkbin = player->pipeline->textbin; + break; + default: + debug_error("requested type is not supportable"); + return FALSE; + break; + } + + if (player->pipeline->mainbin[selectorId].gst) + { + gint n; + + srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src"); + + if (selector->event_probe_id != 0) + gst_pad_remove_probe (srcpad, selector->event_probe_id); + selector->event_probe_id = 0; + + if ((sinkbin) && (sinkbin[sinkId].gst)) + { + sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink"); + + if (srcpad && sinkpad) + { + /* after getting drained signal there is no data flows, so no need to do pad_block */ + debug_log("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad)); + gst_pad_unlink (srcpad, sinkpad); + } + + gst_object_unref (sinkpad); + sinkpad = NULL; + } + gst_object_unref (srcpad); + srcpad = NULL; + + debug_log("selector release"); + + /* release and unref requests pad from the selector */ + for (n = 0; n < selector->channels->len; n++) + { + GstPad *sinkpad = g_ptr_array_index (selector->channels, n); + gst_element_release_request_pad ((player->pipeline->mainbin[selectorId].gst), sinkpad); + } + g_ptr_array_set_size (selector->channels, 0); + + gst_element_set_state (player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst); + + player->pipeline->mainbin[selectorId].gst = NULL; + selector = NULL; + } + + return TRUE; +} + +static void +__mmplayer_deactivate_old_path(mm_player_t *player) +{ + MMPLAYER_FENTER(); + return_if_fail ( player ); + + if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) || + (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) + { + debug_error("deactivate selector error"); + goto ERROR; + } + + _mmplayer_track_destroy(player); + __mmplayer_release_signal_connection( player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG ); + + if (player->streamer) + { + __mm_player_streaming_deinitialize (player->streamer); + __mm_player_streaming_destroy(player->streamer); + player->streamer = NULL; + } + + MMPLAYER_PLAYBACK_LOCK(player); + g_cond_signal( &player->next_play_thread_cond ); + + MMPLAYER_FLEAVE(); + return; + +ERROR: + + if (!player->msg_posted) + { + MMMessageParamType msg = {0,}; + + /*post error*/ + msg.code = MM_ERROR_PLAYER_INTERNAL; + debug_error("next_uri_play> deactivate error"); + + MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg); + player->msg_posted = TRUE; + } + return; +} + +int _mmplayer_set_uri(MMHandleType hplayer, const char* uri) +{ + int result = MM_ERROR_NONE; + mm_player_t* player = (mm_player_t*) hplayer; + MMPLAYER_FENTER(); + + return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri); + if (mmf_attrs_commit(player->attrs)) + { + debug_error("failed to commit the original uri.\n"); + result = MM_ERROR_PLAYER_INTERNAL; + } + else + { + if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE) + { + debug_error("failed to add the original uri in the uri list.\n"); + } + } + + MMPLAYER_FLEAVE(); + return result; +} + +int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path) +{ + mm_player_t* player = (mm_player_t*) hplayer; + guint num_of_list = 0; + + MMPLAYER_FENTER(); + + return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail (uri, MM_ERROR_INVALID_ARGUMENT); + + if (player->pipeline && player->pipeline->textbin) + { + debug_error("subtitle path is enabled.\n"); + return MM_ERROR_PLAYER_INVALID_STATE; + } + + num_of_list = g_list_length(player->uri_info.uri_list); + + if (is_first_path == TRUE) + { + if (num_of_list == 0) + { + player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri)); + debug_log("add original path : %s", uri); + } + else + { + player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0)); + player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0); + + debug_log("change original path : %s", uri); + } + } + else + { + if (num_of_list == 0) + { + MMHandleType attrs = 0; + char *original_uri = NULL; + + attrs = MMPLAYER_GET_ATTRS(player); + if ( attrs ) + { + mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri); + + if (!original_uri) + { + debug_error("there is no original uri."); + return MM_ERROR_PLAYER_INVALID_STATE; + } + + player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri)); + player->uri_info.uri_idx = 0; + + debug_log("add original path at first : %s (%d)", original_uri); + } + } + + player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri)); + debug_log("add new path : %s (total num of list = %d)", uri, g_list_length(player->uri_info.uri_list)); + } + + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; +} + +int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri) +{ + mm_player_t* player = (mm_player_t*) hplayer; + char *next_uri = NULL; + guint num_of_list = 0; + + MMPLAYER_FENTER(); + return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + num_of_list = g_list_length(player->uri_info.uri_list); + + if (num_of_list > 0) + { + gint uri_idx = player->uri_info.uri_idx; + + if ( uri_idx < num_of_list-1 ) + uri_idx++; + else + uri_idx = 0; + + next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx); + debug_error("next uri idx : %d, uri = %s\n", uri_idx, next_uri); + + *uri = g_strdup(next_uri); + } + + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; +} + +static void +__mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, +GstCaps *caps, gpointer data) +{ + mm_player_t* player = (mm_player_t*)data; + const gchar* klass = NULL; + const gchar* mime = NULL; + gchar* caps_str = NULL; + + klass = gst_element_factory_get_metadata (gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS); + mime = gst_structure_get_name (gst_caps_get_structure(caps, 0)); + caps_str = gst_caps_to_string(caps); + + debug_warning("unknown type of caps : %s from %s", + caps_str, GST_ELEMENT_NAME (elem)); + + MMPLAYER_FREEIF(caps_str); + + /* There is no available codec. */ + __mmplayer_check_not_supported_codec (player, klass, mime); +} + +static gboolean +__mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, +GstCaps * caps, gpointer data) +{ + mm_player_t* player = (mm_player_t*)data; + const char* mime = NULL; + gboolean ret = TRUE; + + MMPLAYER_LOG_GST_CAPS_TYPE(caps); + mime = gst_structure_get_name (gst_caps_get_structure(caps, 0)); + + if (g_str_has_prefix(mime, "audio")) { + GstStructure* caps_structure = NULL; + gint samplerate = 0; + gint channels = 0; + gchar *caps_str = NULL; + + caps_structure = gst_caps_get_structure(caps, 0); + gst_structure_get_int (caps_structure, "rate", &samplerate); + gst_structure_get_int (caps_structure, "channels", &channels); + + if ( (channels > 0 && samplerate == 0)) { + debug_log("exclude audio..."); + ret = FALSE; + } + + caps_str = gst_caps_to_string(caps); + /* set it directly because not sent by TAG */ + if (g_strrstr(caps_str, "mobile-xmf")) { + mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf"); + } + MMPLAYER_FREEIF (caps_str); + } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) { + debug_log("already video linked"); + ret = FALSE; + } else { + debug_log("found new stream"); + } + + return ret; +} + +static gint +__mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, +GstCaps* caps, GstElementFactory* factory, gpointer data) +{ + /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed + We are defining our own and will be removed when it actually exposed */ + typedef enum { + GST_AUTOPLUG_SELECT_TRY, + GST_AUTOPLUG_SELECT_EXPOSE, + GST_AUTOPLUG_SELECT_SKIP + } GstAutoplugSelectResult; + + GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY; + mm_player_t* player = (mm_player_t*)data; + + gchar* factory_name = NULL; + gchar* caps_str = NULL; + const gchar* klass = NULL; + gint idx = 0; + + factory_name = GST_OBJECT_NAME (factory); + klass = gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS); + caps_str = gst_caps_to_string(caps); + +// debug_log("found new element [%s] to link for caps [%s]", factory_name, caps_str); + debug_log("found new element [%s] to link", factory_name); + + /* store type string */ + if (player->type == NULL) + { + player->type = gst_caps_to_string(caps); + __mmplayer_update_content_type_info(player); + } + + /* filtering exclude keyword */ + for ( idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++ ) + { + if ( strstr(factory_name, player->ini.exclude_element_keyword[idx] ) ) + { + debug_warning("skipping [%s] by exculde keyword [%s]\n", + factory_name, player->ini.exclude_element_keyword[idx] ); + + // NOTE : does we need to check n_value against the number of item selected? + result = GST_AUTOPLUG_SELECT_SKIP; + goto DONE; + } + } + + /* check factory class for filtering */ + /* NOTE : msl don't need to use image plugins. + * So, those plugins should be skipped for error handling. + */ + if (g_strrstr(klass, "Codec/Decoder/Image")) + { + debug_log("skipping [%s] by not required\n", factory_name); + result = GST_AUTOPLUG_SELECT_SKIP; + goto DONE; + } + + if ((MMPLAYER_IS_ES_BUFF_SRC(player)) && + (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) + { + // TO CHECK : subtitle if needed, add subparse exception. + debug_log("skipping parser/demuxer [%s] in es player by not required\n", factory_name); + result = GST_AUTOPLUG_SELECT_SKIP; + goto DONE; + } + + if (g_strrstr(factory_name, "mpegpsdemux")) + { + debug_log("skipping PS container - not support\n"); + result = GST_AUTOPLUG_SELECT_SKIP; + goto DONE; + } + + if (g_strrstr(factory_name, SMOOTH_STREAMING_DEMUX)) + player->smooth_streaming = TRUE; + + /* check ALP Codec can be used or not */ + if ((g_strrstr(klass, "Codec/Decoder/Audio"))) + { + GstStructure* str = NULL; + gint channels = 0; + + str = gst_caps_get_structure( caps, 0 ); + if ( str ) + { + gst_structure_get_int (str, "channels", &channels); + + debug_log ("check audio ch : %d %d\n", player->max_audio_channels, channels); + if (player->max_audio_channels < channels) + { + player->max_audio_channels = channels; + } + } + + if (!player->audiodec_linked) + { + /* set stream information */ + __mmplayer_set_audio_attrs (player, caps); + } + } + else if ((g_strrstr(klass, "Codec/Decoder/Video"))) + { + if (g_strrstr(factory_name, "omx_")) + { + char *env = getenv ("MM_PLAYER_HW_CODEC_DISABLE"); + if (env != NULL) + { + if (strncasecmp(env, "yes", 3) == 0) + { + debug_log ("skipping [%s] by disabled\n", factory_name); + result = GST_AUTOPLUG_SELECT_SKIP; + goto DONE; + } + } + } + } + + if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) || + (g_strrstr(klass, "Codec/Decoder/Video"))) + { + gint stype = 0; + gint width = 0; + GstStructure *str = NULL; + mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype); + + /* don't make video because of not required */ + if (stype == MM_DISPLAY_SURFACE_NULL) + { + debug_log ("no video because it's not required. -> return expose"); + if (player->set_mode.media_packet_video_stream == FALSE) + { + result = GST_AUTOPLUG_SELECT_EXPOSE; + goto DONE; + } + } + + /* get w/h for omx state-tune */ + str = gst_caps_get_structure (caps, 0); + gst_structure_get_int (str, "width", &width); + + if (width != 0) { + if (player->v_stream_caps) { + gst_caps_unref(player->v_stream_caps); + player->v_stream_caps = NULL; + } + + player->v_stream_caps = gst_caps_copy(caps); + debug_log ("take caps for video state tune"); + MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps); + } + } + + if (g_strrstr(klass, "Decoder")) + { + const char* mime = NULL; + mime = gst_structure_get_name (gst_caps_get_structure(caps, 0)); + + if (g_str_has_prefix(mime, "video")) + { + // __mmplayer_check_video_zero_cpoy(player, factory); + + player->not_supported_codec &= MISSING_PLUGIN_AUDIO; + player->can_support_codec |= FOUND_PLUGIN_VIDEO; + + player->videodec_linked = 1; + } + else if(g_str_has_prefix(mime, "audio")) + { + player->not_supported_codec &= MISSING_PLUGIN_VIDEO; + player->can_support_codec |= FOUND_PLUGIN_AUDIO; + + player->audiodec_linked = 1; + } + } + +DONE: + MMPLAYER_FREEIF(caps_str); + + return result; +} + + +#if 0 +static GValueArray* +__mmplayer_gst_decode_autoplug_factories(GstElement *bin, GstPad* pad, +GstCaps * caps, gpointer data) +{ + //mm_player_t* player = (mm_player_t*)data; + + debug_log("decodebin is requesting factories for caps [%s] from element[%s]", + gst_caps_to_string(caps), + GST_ELEMENT_NAME(GST_PAD_PARENT(pad))); + + return NULL; +} +#endif + +static void +__mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, +gpointer data) // @ +{ + //mm_player_t* player = (mm_player_t*)data; + GstCaps* caps = NULL; + + debug_log("[Decodebin2] pad-removed signal\n"); + + caps = gst_pad_query_caps(new_pad, NULL); + if (caps) + { + gchar* caps_str = NULL; + caps_str = gst_caps_to_string(caps); + + debug_log("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem) ); + + MMPLAYER_FREEIF(caps_str); + } +} + +static void +__mmplayer_gst_decode_drained(GstElement *bin, gpointer data) +{ + mm_player_t* player = (mm_player_t*)data; + + MMPLAYER_FENTER(); + return_if_fail ( player ); + + debug_log("__mmplayer_gst_decode_drained"); + + if (player->use_deinterleave == TRUE) + { + debug_log("group playing mode."); + return; + } + + if (!g_mutex_trylock(&player->cmd_lock)) + { + debug_warning("Fail to get cmd lock"); + return; + } + + if (!__mmplayer_verify_next_play_path(player)) + { + debug_log("decoding is finished."); + player->gapless.running = FALSE; + player->gapless.start_time = 0; + g_mutex_unlock(&player->cmd_lock); + return; + } + + player->gapless.reconfigure = TRUE; + + /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/ + __mmplayer_deactivate_old_path(player); + + g_mutex_unlock(&player->cmd_lock); + + MMPLAYER_FLEAVE(); +} + +static void +__mmplayer_gst_element_added (GstElement *bin, GstElement *element, gpointer data) +{ + mm_player_t* player = (mm_player_t*)data; + const gchar* klass = NULL; + gchar* factory_name = NULL; + + klass = gst_element_factory_get_metadata (gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS); + factory_name = GST_OBJECT_NAME (gst_element_get_factory(element)); + + debug_log("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element)); + + if (__mmplayer_add_dump_buffer_probe(player, element)) + debug_log("add buffer probe"); + + //<- + if (g_strrstr(klass, "Codec/Decoder/Audio")) + { + gchar* selected = NULL; + selected = g_strdup( GST_ELEMENT_NAME(element)); + player->audio_decoders = g_list_append (player->audio_decoders, selected); + } + //-> temp code + + if (g_strrstr(klass, "Parser")) + { + gchar* selected = NULL; + + selected = g_strdup (factory_name); + player->parsers = g_list_append (player->parsers, selected); + } + + if ((g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) && !(g_strrstr(klass, "Adaptive"))) + { + /* FIXIT : first value will be overwritten if there's more + * than 1 demuxer/parser + */ + + //debug_log ("plugged element is demuxer. take it\n"); + player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX; + player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element; + + /*Added for multi audio support */ // Q. del? + if (g_strrstr(klass, "Demux")) + { + player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX; + player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element; + } + } + + if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) + { + int surface_type = 0; + + mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type); + +#if 0 // this is for 0.10 plugin with downstream modification + /* playback protection if drm file */ + if (player->use_video_stream || surface_type == MM_DISPLAY_SURFACE_EVAS || surface_type == MM_DISPLAY_SURFACE_X_EXT) + { + debug_log("playback can be protected if playready drm"); + g_object_set (G_OBJECT(element), "playback-protection", TRUE, NULL); + } +#endif + } + + // to support trust-zone only + if (g_strrstr(factory_name, "asfdemux")) + { + debug_log ("set file-location %s\n", player->profile.uri); + g_object_set (G_OBJECT(element), "file-location", player->profile.uri, NULL); + + if (player->video_hub_download_mode == TRUE) + { + g_object_set (G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL); + } + } + else if (g_strrstr(factory_name, "legacyh264parse")) // SMOOTH_STREAMING_DEMUX + { + debug_log ("[%s] output-format to legacyh264parse\n", SMOOTH_STREAMING_DEMUX); + g_object_set (G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */ + } + else if (g_strrstr(factory_name, "mpegaudioparse")) + { + if ((MMPLAYER_IS_HTTP_STREAMING(player)) && + (__mmplayer_is_only_mp3_type(player->type))) + { + debug_log ("[mpegaudioparse] set streaming pull mode."); + g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL); + } + } + else if (g_strrstr(factory_name, "omx")) + { + if (g_strrstr(klass, "Codec/Decoder/Video")) + { + gboolean ret = FALSE; + + if (player->v_stream_caps != NULL) + { + GstPad *pad = gst_element_get_static_pad(element, "sink"); + + if (pad) + { + ret = gst_pad_set_caps(pad, player->v_stream_caps); + debug_log("found omx decoder, setting gst_pad_set_caps for omx (ret:%d)", ret); + MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps); + gst_object_unref (pad); + } + } + g_object_set (G_OBJECT(element), "state-tuning", TRUE, NULL); + } +#ifdef _MM_PLAYER_ALP_PARSER + if (g_strrstr(factory_name, "omx_mp3dec")) + { + g_list_foreach (player->parsers, check_name, player); + } +#endif + player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element; + } + + if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) && + (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) + { + debug_log ("plugged element is multiqueue. take it\n"); + + player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER; + player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element; + + if ((MMPLAYER_IS_HTTP_STREAMING(player)) || + (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))) + { + /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/ + __mm_player_streaming_set_multiqueue(player->streamer, + element, + TRUE, + player->ini.http_buffering_time, + 1.0, + player->ini.http_buffering_limit); + + __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst); + } + } + + MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-added" ); + return; +} + +static gboolean __mmplayer_configure_audio_callback(mm_player_t* player) +{ + MMPLAYER_FENTER(); + return_val_if_fail ( player, FALSE ); + + if ( MMPLAYER_IS_STREAMING(player) ) + return FALSE; + + /* This callback can be set to music player only. */ + if((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) + { + debug_warning("audio callback is not supported for video"); + return FALSE; + } + + if (player->audio_stream_cb) + { + { + GstPad *pad = NULL; + + pad = gst_element_get_static_pad (player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink"); + + if ( !pad ) + { + debug_error("failed to get sink pad from audiosink to probe data\n"); + return FALSE; + } + player->audio_cb_probe_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, + __mmplayer_audio_stream_probe, player, NULL); + + gst_object_unref (pad); + + pad = NULL; + } + } + else + { + debug_error("There is no audio callback to configure.\n"); + return FALSE; + } + + MMPLAYER_FLEAVE(); + + return TRUE; +} + +static void +__mmplayer_init_factories(mm_player_t* player) // @ +{ + return_if_fail ( player ); + + player->factories = gst_registry_feature_filter(gst_registry_get(), + (GstPluginFeatureFilter)__mmplayer_feature_filter, FALSE, NULL); + player->factories = g_list_sort(player->factories, (GCompareFunc)util_factory_rank_compare); +} + +static void +__mmplayer_release_factories(mm_player_t* player) // @ +{ + MMPLAYER_FENTER(); + return_if_fail ( player ); + + if (player->factories) + { + gst_plugin_feature_list_free (player->factories); + player->factories = NULL; + } + + MMPLAYER_FLEAVE(); +} + +static void +__mmplayer_release_misc(mm_player_t* player) +{ + int i; + gboolean cur_mode = player->set_mode.rich_audio; + MMPLAYER_FENTER(); + + return_if_fail ( player ); + + player->use_video_stream = FALSE; + player->video_stream_cb = NULL; + player->video_stream_cb_user_param = NULL; + + player->audio_stream_cb = NULL; + player->audio_stream_render_cb_ex = NULL; + player->audio_stream_cb_user_param = NULL; + player->audio_stream_sink_sync = false; + + player->video_stream_changed_cb = NULL; + player->video_stream_changed_cb_user_param = NULL; + + player->audio_stream_changed_cb = NULL; + player->audio_stream_changed_cb_user_param = NULL; + + player->sent_bos = FALSE; + player->playback_rate = DEFAULT_PLAYBACK_RATE; + + player->doing_seek = FALSE; + + player->updated_bitrate_count = 0; + player->total_bitrate = 0; + player->updated_maximum_bitrate_count = 0; + player->total_maximum_bitrate = 0; + + player->not_found_demuxer = 0; + + player->last_position = 0; + player->duration = 0; + player->http_content_size = 0; + player->not_supported_codec = MISSING_PLUGIN_NONE; + player->can_support_codec = FOUND_PLUGIN_NONE; + player->pending_seek.is_pending = FALSE; + player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME; + player->pending_seek.pos = 0; + player->msg_posted = FALSE; + player->has_many_types = FALSE; + player->is_drm_file = FALSE; + player->max_audio_channels = 0; + player->video_share_api_delta = 0; + player->video_share_clock_delta = 0; + player->sound_focus.keep_last_pos = FALSE; + player->sound_focus.acquired = FALSE; + player->is_subtitle_force_drop = FALSE; + player->play_subtitle = FALSE; + player->use_textoverlay = FALSE; + player->adjust_subtitle_pos = 0; + player->last_multiwin_status = FALSE; + player->has_closed_caption = FALSE; + player->set_mode.media_packet_video_stream = FALSE; + memset(&player->set_mode, 0, sizeof(MMPlayerSetMode)); + /* recover mode */ + player->set_mode.rich_audio = cur_mode; + + for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) + { + player->bitrate[i] = 0; + player->maximum_bitrate[i] = 0; + } + + /* remove media stream cb (appsrc cb) */ + for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) + { + player->media_stream_buffer_status_cb[i] = NULL; + player->media_stream_seek_data_cb[i] = NULL; + } + + /* free memory related to audio effect */ + MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin); + + if (player->state_tune_caps) + { + gst_caps_unref(player->state_tune_caps); + player->state_tune_caps = NULL; + } + + if (player->video_cb_probe_id) + { + GstPad *pad = NULL; + + pad = gst_element_get_static_pad (player->video_fakesink, "sink"); + + if (pad) { + debug_log("release video probe\n"); + + /* release audio callback */ + gst_pad_remove_probe (pad, player->video_cb_probe_id); + player->video_cb_probe_id = 0; + player->video_stream_cb = NULL; + player->video_stream_cb_user_param = NULL; + } + } + + MMPLAYER_FLEAVE(); +} + +static void +__mmplayer_release_misc_post(mm_player_t* player) +{ + char *original_uri = NULL; + MMPLAYER_FENTER(); + + /* player->pipeline is already released before. */ + + return_if_fail ( player ); + + mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0); + mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0); + + /* clean found parsers */ + if (player->parsers) + { + GList *parsers = player->parsers; + for ( ;parsers ; parsers = g_list_next(parsers)) + { + gchar *name = parsers->data; + MMPLAYER_FREEIF(name); + } + g_list_free(player->parsers); + player->parsers = NULL; + } + + /* clean found audio decoders */ + if (player->audio_decoders) + { + GList *a_dec = player->audio_decoders; + for ( ;a_dec ; a_dec = g_list_next(a_dec)) + { + gchar *name = a_dec->data; + MMPLAYER_FREEIF(name); + } + g_list_free(player->audio_decoders); + player->audio_decoders = NULL; + } + + /* clean the uri list except original uri */ + if (player->uri_info.uri_list) + { + original_uri = g_list_nth_data(player->uri_info.uri_list, 0); + + if (player->attrs) + { + mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri); + debug_log("restore original uri = %s\n", original_uri); + + if (mmf_attrs_commit(player->attrs)) + { + debug_error("failed to commit the original uri.\n"); + } + } + + GList *uri_list = player->uri_info.uri_list; + for ( ;uri_list ; uri_list = g_list_next(uri_list)) + { + gchar *uri = uri_list->data; + MMPLAYER_FREEIF(uri); + } + g_list_free(player->uri_info.uri_list); + player->uri_info.uri_list = NULL; + } + + player->uri_info.uri_idx = 0; + MMPLAYER_FLEAVE(); +} + +static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name) +{ + GstElement *element = NULL; + GstPad *sinkpad; + + debug_log("creating %s to plug\n", name); + + element = gst_element_factory_make(name, NULL); + if ( ! element ) + { + debug_error("failed to create queue\n"); + return NULL; + } + + if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY) ) + { + debug_error("failed to set state READY to %s\n", name); + gst_object_unref (element); + return NULL; + } + + if ( ! gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) + { + debug_error("failed to add %s\n", name); + gst_object_unref (element); + return NULL; + } + + sinkpad = gst_element_get_static_pad(element, "sink"); + + if ( GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad) ) + { + debug_error("failed to link %s\n", name); + gst_object_unref (sinkpad); + gst_object_unref (element); + return NULL; + } + + debug_log("linked %s to pipeline successfully\n", name); + + gst_object_unref (sinkpad); + + return element; +} + +static gboolean +__mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement, +const char *padname, const GList *templlist) +{ + GstPad *pad = NULL; + gboolean has_dynamic_pads = FALSE; + gboolean has_many_types = FALSE; + const char *klass = NULL; + GstStaticPadTemplate *padtemplate = NULL; + GstElementFactory *factory = NULL; + GstElement* queue = NULL; + GstElement* parser = NULL; + GstPad *pssrcpad = NULL; + GstPad *qsrcpad = NULL, *qsinkpad = NULL; + MMPlayerGstElement *mainbin = NULL; + GstStructure* str = NULL; + GstCaps* srccaps = NULL; + GstState target_state = GST_STATE_READY; + gboolean isvideo_decoder = FALSE; + guint q_max_size_time = 0; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player && + player->pipeline && + player->pipeline->mainbin, + FALSE ); + + mainbin = player->pipeline->mainbin; + + debug_log("plugging pad %s:%s to newly create %s:%s\n", + GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad ) ), + GST_PAD_NAME( srcpad ), + GST_ELEMENT_NAME( sinkelement ), + padname); + + factory = gst_element_get_factory(sinkelement); + klass = gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS); + + /* check if player can do start continually */ + MMPLAYER_CHECK_CMD_IF_EXIT(player); + + /* need it to warm up omx before linking to pipeline */ + if (g_strrstr(GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad ) ), "demux")) + { + debug_log("get demux caps.\n"); + if (player->state_tune_caps) + { + gst_caps_unref(player->state_tune_caps); + player->state_tune_caps = NULL; + } + player->state_tune_caps = gst_caps_copy(gst_pad_get_current_caps(srcpad)); + } + + /* NOTE : OMX Codec can check if resource is available or not at this state. */ + if (g_strrstr(GST_ELEMENT_NAME(sinkelement), "omx")) + { + if (player->state_tune_caps != NULL) + { + debug_log("set demux's caps to omx codec if resource is available"); + if (gst_pad_set_caps(gst_element_get_static_pad(sinkelement, "sink"), player->state_tune_caps)) + { + target_state = GST_STATE_PAUSED; + isvideo_decoder = TRUE; + g_object_set(G_OBJECT(sinkelement), "state-tuning", TRUE, NULL); + } + else + { + debug_warning("failed to set caps for state tuning"); + } + } + gst_caps_unref(player->state_tune_caps); + player->state_tune_caps = NULL; + } + + if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, target_state) ) + { + debug_error("failed to set %d state to %s\n", target_state, GST_ELEMENT_NAME( sinkelement )); + if (isvideo_decoder) + { + gst_element_set_state(sinkelement, GST_STATE_NULL); + gst_object_unref(G_OBJECT(sinkelement)); + player->keep_detecting_vcodec = TRUE; + } + goto ERROR; + } + + /* add to pipeline */ + if ( ! gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), sinkelement) ) + { + debug_error("failed to add %s to mainbin\n", GST_ELEMENT_NAME( sinkelement )); + goto ERROR; + } + + debug_log("element klass : %s\n", klass); + + /* added to support multi track files */ + /* only decoder case and any of the video/audio still need to link*/ + if(g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player,srcpad)) + { + gchar *name = g_strdup(GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad ))); + + if (g_strrstr(name, "mpegtsdemux")|| g_strrstr(name, SMOOTH_STREAMING_DEMUX)) + { + gchar *src_demux_caps_str = NULL; + gchar *needed_parser = NULL; + GstCaps *src_demux_caps = NULL; + gboolean smooth_streaming = FALSE; + + src_demux_caps = gst_pad_query_caps(srcpad, NULL); + src_demux_caps_str = gst_caps_to_string(src_demux_caps); + + gst_caps_unref(src_demux_caps); + + if (g_strrstr(src_demux_caps_str, "video/x-h264")) + { + if (g_strrstr(name, SMOOTH_STREAMING_DEMUX)) + { + needed_parser = g_strdup("legacyh264parse"); + smooth_streaming = TRUE; + } + else + { + needed_parser = g_strdup("h264parse"); + } + } + else if (g_strrstr(src_demux_caps_str, "video/mpeg")) + { + needed_parser = g_strdup("mpeg4videoparse"); + } + MMPLAYER_FREEIF(src_demux_caps_str); + + if (needed_parser) + { + parser = __mmplayer_element_create_and_link(player, srcpad, needed_parser); + MMPLAYER_FREEIF(needed_parser); + + if ( !parser ) + { + debug_error("failed to create parser\n"); + } + else + { + if (smooth_streaming) + { + g_object_set (parser, "output-format", 1, NULL); /* NALU/Byte Stream format */ + } + + /* update srcpad if parser is created */ + pssrcpad = gst_element_get_static_pad(parser, "src"); + srcpad = pssrcpad; + } + } + } + MMPLAYER_FREEIF(name); + + queue = __mmplayer_element_create_and_link(player, srcpad, "queue"); // parser - queue or demuxer - queue + if ( ! queue ) + { + debug_error("failed to create queue\n"); + goto ERROR; + } + + /* update srcpad to link with decoder */ + qsrcpad = gst_element_get_static_pad(queue, "src"); + srcpad = qsrcpad; + + q_max_size_time = GST_QUEUE_DEFAULT_TIME; + + /* assigning queue handle for futher manipulation purpose */ + /* FIXIT : make it some kind of list so that msl can support more then two stream (text, data, etc...) */ + if(mainbin[MMPLAYER_M_Q1].gst == NULL) + { + mainbin[MMPLAYER_M_Q1].id = MMPLAYER_M_Q1; + mainbin[MMPLAYER_M_Q1].gst = queue; + + if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) + { + g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-time", 0 , NULL); + g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-buffers", 2, NULL); + g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-bytes", 0, NULL); + } + else + { + if (!MMPLAYER_IS_RTSP_STREAMING(player)) + g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL); + } + } + else if(mainbin[MMPLAYER_M_Q2].gst == NULL) + { + mainbin[MMPLAYER_M_Q2].id = MMPLAYER_M_Q2; + mainbin[MMPLAYER_M_Q2].gst = queue; + + if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) + { + g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-time", 0 , NULL); + g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-buffers", 2, NULL); + g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-bytes", 0, NULL); + } + else + { + if (!MMPLAYER_IS_RTSP_STREAMING(player)) + g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL); + } + } + else + { + debug_error("Not supporting more then two elementary stream\n"); + g_assert(1); + } + + pad = gst_element_get_static_pad(sinkelement, padname); + + if ( ! pad ) + { + debug_warning("failed to get pad(%s) from %s. retrying with [sink]\n", + padname, GST_ELEMENT_NAME(sinkelement) ); + + pad = gst_element_get_static_pad(sinkelement, "sink"); + if ( ! pad ) + { + debug_error("failed to get pad(sink) from %s. \n", + GST_ELEMENT_NAME(sinkelement) ); + goto ERROR; + } + } + + /* to check the video/audio type set the proper flag*/ + const gchar *mime_type = NULL; + { + srccaps = gst_pad_query_caps(srcpad, NULL); + if ( !srccaps ) + goto ERROR; + + str = gst_caps_get_structure( srccaps, 0 ); + if ( ! str ) + goto ERROR; + + mime_type = gst_structure_get_name(str); + if ( ! mime_type ) + goto ERROR; + } + + /* link queue and decoder. so, it will be queue - decoder. */ + if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, pad) ) + { + gst_object_unref(GST_OBJECT(pad)); + debug_error("failed to link (%s) to pad(%s)\n", GST_ELEMENT_NAME( sinkelement ), padname ); + + /* reconstitute supportable codec */ + if (strstr(mime_type, "video")) + { + player->can_support_codec ^= FOUND_PLUGIN_VIDEO; + } + else if (strstr(mime_type, "audio")) + { + player->can_support_codec ^= FOUND_PLUGIN_AUDIO; + } + goto ERROR; + } + + if (strstr(mime_type, "video")) + { + player->videodec_linked = 1; + debug_msg("player->videodec_linked set to 1\n"); + + } + else if (strstr(mime_type, "audio")) + { + player->audiodec_linked = 1; + debug_msg("player->auddiodec_linked set to 1\n"); + } + + gst_object_unref(GST_OBJECT(pad)); + gst_caps_unref(GST_CAPS(srccaps)); + srccaps = NULL; + } + + if ( !MMPLAYER_IS_HTTP_PD(player) ) + { + if( (g_strrstr(klass, "Demux") && !g_strrstr(klass, "Metadata")) || (g_strrstr(klass, "Parser") ) ) + { + if (MMPLAYER_IS_HTTP_STREAMING(player)) + { + gint64 dur_bytes = 0L; + gchar *file_buffering_path = NULL; + gboolean use_file_buffer = FALSE; + + if ( !mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) + { + debug_log("creating http streaming buffering queue\n"); + + queue = gst_element_factory_make("queue2", "queue2"); + if ( ! queue ) + { + debug_error ( "failed to create buffering queue element\n" ); + goto ERROR; + } + + if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY) ) + { + debug_error("failed to set state READY to buffering queue\n"); + goto ERROR; + } + + if ( !gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue) ) + { + debug_error("failed to add buffering queue\n"); + goto ERROR; + } + + qsinkpad = gst_element_get_static_pad(queue, "sink"); + qsrcpad = gst_element_get_static_pad(queue, "src"); + + if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, qsinkpad) ) + { + debug_error("failed to link buffering queue\n"); + goto ERROR; + } + srcpad = qsrcpad; + + + mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER; + mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue; + + if ( !MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) + { + if ( !gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes)) + debug_error("fail to get duration.\n"); + + if (dur_bytes > 0) + { + use_file_buffer = MMPLAYER_USE_FILE_FOR_BUFFERING(player); + file_buffering_path = g_strdup(player->ini.http_file_buffer_path); + } + else + { + dur_bytes = 0; + } + } + + /* NOTE : we cannot get any duration info from ts container in case of streaming */ + if(!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux")) + { + __mm_player_streaming_set_queue2(player->streamer, + queue, + TRUE, + player->ini.http_max_size_bytes, + player->ini.http_buffering_time, + 1.0, + player->ini.http_buffering_limit, + use_file_buffer, + file_buffering_path, + (guint64)dur_bytes); + } + + MMPLAYER_FREEIF(file_buffering_path); + } + } + } + } + /* if it is not decoder or */ + /* in decoder case any of the video/audio still need to link*/ + if(!g_strrstr(klass, "Decoder")) + { + + pad = gst_element_get_static_pad(sinkelement, padname); + if ( ! pad ) + { + debug_warning("failed to get pad(%s) from %s. retrying with [sink]\n", + padname, GST_ELEMENT_NAME(sinkelement) ); + + pad = gst_element_get_static_pad(sinkelement, "sink"); + + if ( ! pad ) + { + debug_error("failed to get pad(sink) from %s. \n", + GST_ELEMENT_NAME(sinkelement) ); + goto ERROR; + } + } + + if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, pad) ) + { + gst_object_unref(GST_OBJECT(pad)); + debug_error("failed to link (%s) to pad(%s)\n", GST_ELEMENT_NAME( sinkelement ), padname ); + goto ERROR; + } + + gst_object_unref(GST_OBJECT(pad)); + } + + for(;templlist != NULL; templlist = templlist->next) + { + padtemplate = templlist->data; + + debug_log ("director = [%d], presence = [%d]\n", padtemplate->direction, padtemplate->presence); + + if( padtemplate->direction != GST_PAD_SRC || + padtemplate->presence == GST_PAD_REQUEST ) + continue; + + switch(padtemplate->presence) + { + case GST_PAD_ALWAYS: + { + GstPad *srcpad = gst_element_get_static_pad(sinkelement, "src"); + GstCaps *caps = gst_pad_query_caps(srcpad, NULL); + + /* Check whether caps has many types */ + if ( !gst_caps_is_fixed(caps)) + { + debug_log ("always pad but, caps has many types"); + MMPLAYER_LOG_GST_CAPS_TYPE(caps); + has_many_types = TRUE; + break; + } + + if ( ! __mmplayer_try_to_plug(player, srcpad, caps) ) + { + gst_object_unref(GST_OBJECT(srcpad)); + gst_caps_unref(GST_CAPS(caps)); + + debug_error("failed to plug something after %s\n", GST_ELEMENT_NAME( sinkelement )); + goto ERROR; + } + + gst_caps_unref(GST_CAPS(caps)); + gst_object_unref(GST_OBJECT(srcpad)); + + } + break; + + + case GST_PAD_SOMETIMES: + has_dynamic_pads = TRUE; + break; + + default: + break; + } + } + + /* check if player can do start continually */ + MMPLAYER_CHECK_CMD_IF_EXIT(player); + + if( has_dynamic_pads ) + { + player->have_dynamic_pad = TRUE; + MMPLAYER_SIGNAL_CONNECT ( player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", + G_CALLBACK(__mmplayer_add_new_pad), player); + + /* for streaming, more then one typefind will used for each elementary stream + * so this doesn't mean the whole pipeline completion + */ + if ( ! MMPLAYER_IS_RTSP_STREAMING( player ) ) + { + MMPLAYER_SIGNAL_CONNECT( player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", + G_CALLBACK(__mmplayer_pipeline_complete), player); + } + } + + if (has_many_types) + { + GstPad *pad = NULL; + + player->has_many_types = has_many_types; + + pad = gst_element_get_static_pad(sinkelement, "src"); + MMPLAYER_SIGNAL_CONNECT (player, pad, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "notify::caps", G_CALLBACK(__mmplayer_add_new_caps), player); + gst_object_unref (GST_OBJECT(pad)); + } + + + /* check if player can do start continually */ + MMPLAYER_CHECK_CMD_IF_EXIT(player); + + if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, GST_STATE_PAUSED) ) + { + debug_error("failed to set state PAUSED to %s\n", GST_ELEMENT_NAME( sinkelement )); + goto ERROR; + } + + if ( queue ) + { + if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (queue, GST_STATE_PAUSED) ) + { + debug_error("failed to set state PAUSED to queue\n"); + goto ERROR; + } + + queue = NULL; + + gst_object_unref (GST_OBJECT(qsrcpad)); + qsrcpad = NULL; + } + + if ( parser ) + { + if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (parser, GST_STATE_PAUSED) ) + { + debug_error("failed to set state PAUSED to queue\n"); + goto ERROR; + } + + parser = NULL; + + gst_object_unref (GST_OBJECT(pssrcpad)); + pssrcpad = NULL; + } + + MMPLAYER_FLEAVE(); + + return TRUE; + +ERROR: + + if ( queue ) + { + gst_object_unref(GST_OBJECT(qsrcpad)); + + /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state. + * You need to explicitly set elements to the NULL state before + * dropping the final reference, to allow them to clean up. + */ + gst_element_set_state(queue, GST_STATE_NULL); + /* And, it still has a parent "player". + * You need to let the parent manage the object instead of unreffing the object directly. + */ + + gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue); + //gst_object_unref( queue ); + } + + if ( srccaps ) + gst_caps_unref(GST_CAPS(srccaps)); + + return FALSE; +} + +static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data) // @ +{ + const gchar *klass; + //const gchar *name; + + /* we only care about element factories */ + if (!GST_IS_ELEMENT_FACTORY(feature)) + return FALSE; + + /* only parsers, demuxers and decoders */ + klass = gst_element_factory_get_metadata (GST_ELEMENT_FACTORY(feature), GST_ELEMENT_METADATA_KLASS); + //name = gst_element_factory_get_longname(GST_ELEMENT_FACTORY(feature)); + + if( g_strrstr(klass, "Demux") == NULL && + g_strrstr(klass, "Codec/Decoder") == NULL && + g_strrstr(klass, "Depayloader") == NULL && + g_strrstr(klass, "Parse") == NULL) + { + return FALSE; + } + return TRUE; +} + + +static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data) +{ + mm_player_t* player = (mm_player_t*) data; + GstCaps *caps = NULL; + GstStructure *str = NULL; + const char *name; + + MMPLAYER_FENTER(); + + return_if_fail ( pad ) + return_if_fail ( unused ) + return_if_fail ( data ) + + caps = gst_pad_query_caps(pad, NULL); + if ( !caps ) + return; + + str = gst_caps_get_structure(caps, 0); + if ( !str ) + return; + + name = gst_structure_get_name(str); + if ( !name ) + return; + debug_log("name=%s\n", name); + + if ( ! __mmplayer_try_to_plug(player, pad, caps) ) + { + debug_error("failed to autoplug for type (%s)\n", name); + gst_caps_unref(caps); + return; + } + + gst_caps_unref(caps); + + __mmplayer_pipeline_complete( NULL, (gpointer)player ); + + MMPLAYER_FLEAVE(); + + return; +} + +static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps) +{ + GstStructure *str; + gint version = 0; + const char *stream_type; + gchar *version_field = NULL; + + MMPLAYER_FENTER(); + + return_if_fail ( player ); + return_if_fail ( caps ); + + str = gst_caps_get_structure(caps, 0); + if ( !str ) + return; + + stream_type = gst_structure_get_name(str); + if ( !stream_type ) + return; + + + /* set unlinked mime type for downloadable codec */ + if (g_str_has_prefix(stream_type, "video/")) + { + if (g_str_has_prefix(stream_type, "video/mpeg")) + { + gst_structure_get_int (str, MM_PLAYER_MPEG_VNAME, &version); + version_field = MM_PLAYER_MPEG_VNAME; + } + else if (g_str_has_prefix(stream_type, "video/x-wmv")) + { + gst_structure_get_int (str, MM_PLAYER_WMV_VNAME, &version); + version_field = MM_PLAYER_WMV_VNAME; + + } + else if (g_str_has_prefix(stream_type, "video/x-divx")) + { + gst_structure_get_int (str, MM_PLAYER_DIVX_VNAME, &version); + version_field = MM_PLAYER_DIVX_VNAME; + } + + if (version) + { + player->unlinked_video_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version); + } + else + { + player->unlinked_video_mime = g_strdup_printf("%s", stream_type); + } + } + else if (g_str_has_prefix(stream_type, "audio/")) + { + if (g_str_has_prefix(stream_type, "audio/mpeg")) // mp3 or aac + { + gst_structure_get_int (str, MM_PLAYER_MPEG_VNAME, &version); + version_field = MM_PLAYER_MPEG_VNAME; + } + else if (g_str_has_prefix(stream_type, "audio/x-wma")) + { + gst_structure_get_int (str, MM_PLAYER_WMA_VNAME, &version); + version_field = MM_PLAYER_WMA_VNAME; + } + + if (version) + { + player->unlinked_audio_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version); + } + else + { + player->unlinked_audio_mime = g_strdup_printf("%s", stream_type); + } + } + + MMPLAYER_FLEAVE(); +} + +static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data) +{ + mm_player_t* player = (mm_player_t*) data; + GstCaps *caps = NULL; + GstStructure *str = NULL; + const char *name; + + MMPLAYER_FENTER(); + return_if_fail ( player ); + return_if_fail ( pad ); + + GST_OBJECT_LOCK (pad); + if ((caps = gst_pad_get_current_caps(pad))) + gst_caps_ref(caps); + GST_OBJECT_UNLOCK (pad); + + if ( NULL == caps ) + { + caps = gst_pad_query_caps(pad, NULL); + if ( !caps ) return; + } + + MMPLAYER_LOG_GST_CAPS_TYPE(caps); + + str = gst_caps_get_structure(caps, 0); + if ( !str ) + return; + + name = gst_structure_get_name(str); + if ( !name ) + return; + + player->num_dynamic_pad++; + debug_log("stream count inc : %d\n", player->num_dynamic_pad); + + /* Note : If the stream is the subtitle, we try not to play it. Just close the demuxer subtitle pad. + * If want to play it, remove this code. + */ + if (g_strrstr(name, "application")) + { + if (g_strrstr(name, "x-id3") || g_strrstr(name, "x-apetag")) + { + /* If id3/ape tag comes, keep going */ + debug_log("application mime exception : id3/ape tag"); + } + else + { + /* Otherwise, we assume that this stream is subtile. */ + debug_log(" application mime type pad is closed."); + return; + } + } + else if (g_strrstr(name, "audio")) + { + gint samplerate = 0, channels = 0; + + if (player->audiodec_linked) + { + gst_caps_unref(caps); + debug_log("multi tracks. skip to plug"); + return; + } + + /* set stream information */ + /* if possible, set it here because the caps is not distrubed by resampler. */ + gst_structure_get_int (str, "rate", &samplerate); + mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate); + + gst_structure_get_int (str, "channels", &channels); + mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels); + + debug_log("audio samplerate : %d channels : %d", samplerate, channels); + } + else if (g_strrstr(name, "video")) + { + gint stype; + mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype); + + /* don't make video because of not required */ + if (stype == MM_DISPLAY_SURFACE_NULL) + { + debug_log("no video because it's not required"); + return; + } + + player->v_stream_caps = gst_caps_copy(caps); //if needed, video caps is required when videobin is created + } + + if ( ! __mmplayer_try_to_plug(player, pad, caps) ) + { + debug_error("failed to autoplug for type (%s)", name); + + __mmplayer_set_unlinked_mime_type(player, caps); + } + + gst_caps_unref(caps); + + MMPLAYER_FLEAVE(); + return; +} + +gboolean +__mmplayer_check_subtitle( mm_player_t* player ) +{ + MMHandleType attrs = 0; + char *subtitle_uri = NULL; + + MMPLAYER_FENTER(); + + return_val_if_fail( player, FALSE ); + + /* get subtitle attribute */ + attrs = MMPLAYER_GET_ATTRS(player); + if ( !attrs ) + return FALSE; + + mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri); + if ( !subtitle_uri || !strlen(subtitle_uri)) + return FALSE; + + debug_log ("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri)); + player->is_external_subtitle_present = TRUE; + + MMPLAYER_FLEAVE(); + + return TRUE; +} + +static gboolean +__mmplayer_can_extract_pcm( mm_player_t* player ) +{ + MMHandleType attrs = 0; + gboolean is_drm = FALSE; + gboolean sound_extraction = FALSE; + + return_val_if_fail ( player, FALSE ); + + attrs = MMPLAYER_GET_ATTRS(player); + if ( !attrs ) + { + debug_error("fail to get attributes."); + return FALSE; + } + + /* check file is drm or not */ + if (g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm")) + g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm", &is_drm, NULL); + + /* get sound_extraction property */ + mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction); + + if ( ! sound_extraction || is_drm ) + { + debug_log("checking pcm extraction mode : %d, drm : %d", sound_extraction, is_drm); + return FALSE; + } + + return TRUE; +} + +static gboolean +__mmplayer_handle_streaming_error ( mm_player_t* player, GstMessage * message ) +{ + debug_log("\n"); + MMMessageParamType msg_param; + gchar *msg_src_element = NULL; + GstStructure *s = NULL; + guint error_id = 0; + gchar *error_string = NULL; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, FALSE ); + return_val_if_fail ( message, FALSE ); + + s = malloc( sizeof(GstStructure) ); + memcpy ( s, gst_message_get_structure ( message ), sizeof(GstStructure)); + + if ( !gst_structure_get_uint (s, "error_id", &error_id) ) + error_id = MMPLAYER_STREAMING_ERROR_NONE; + + switch ( error_id ) + { + case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO: + msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO; + break; + case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO: + msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO; + break; + case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL: + msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL; + break; + case MMPLAYER_STREAMING_ERROR_DNS_FAIL: + msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL; + break; + case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED: + msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED; + break; + case MMPLAYER_STREAMING_ERROR_BAD_SERVER: + msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER; + break; + case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL: + msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL; + break; + case MMPLAYER_STREAMING_ERROR_INVALID_URL: + msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL; + break; + case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG: + msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG; + break; + case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES: + msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES; + break; + case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT: + msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT; + break; + case MMPLAYER_STREAMING_ERROR_BAD_REQUEST: + msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST; + break; + case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED: + msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED; + break; + case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED: + msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED; + break; + case MMPLAYER_STREAMING_ERROR_FORBIDDEN: + msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN; + break; + case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND: + msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND; + break; + case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED: + msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED; + break; + case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE: + msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE; + break; + case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED: + msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED; + break; + case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT: + msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT; + break; + case MMPLAYER_STREAMING_ERROR_GONE: + msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE; + break; + case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED: + msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED; + break; + case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED: + msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED; + break; + case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE: + msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE; + break; + case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE: + msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE; + break; + case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE: + msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE; + break; + case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD: + msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD; + break; + case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND: + msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND; + break; + case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH: + msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH; + break; + case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID: + msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID; + break; + case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE: + msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE; + break; + case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE: + msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE; + break; + case MMPLAYER_STREAMING_ERROR_INVALID_RANGE: + msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE; + break; + case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY: + msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY; + break; + case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED: + msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED; + break; + case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED: + msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED; + break; + case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT: + msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT; + break; + case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE: + msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE; + break; + case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR: + msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR; + break; + case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED: + msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED; + break; + case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY: + msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY; + break; + case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE: + msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE; + break; + case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT: + msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT; + break; + case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED: + msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED; + break; + case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED: + msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED; + break; + default: + { + MMPLAYER_FREEIF(s); + return MM_ERROR_PLAYER_STREAMING_FAIL; + } + } + + error_string = g_strdup(gst_structure_get_string (s, "error_string")); + if ( error_string ) + msg_param.data = (void *) error_string; + + if ( message->src ) + { + msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( message->src ) ); + + debug_error("-Msg src : [%s] Code : [%x] Error : [%s] \n", + msg_src_element, msg_param.code, (char*)msg_param.data ); + } + + /* post error to application */ + if ( ! player->msg_posted ) + { + MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param ); + + /* don't post more if one was sent already */ + player->msg_posted = TRUE; + } + else + { + debug_log("skip error post because it's sent already.\n"); + } + + MMPLAYER_FREEIF(s); + MMPLAYER_FLEAVE(); + g_free(error_string); + + return TRUE; + +} + +static void +__mmplayer_handle_eos_delay( mm_player_t* player, int delay_in_ms ) +{ + return_if_fail( player ); + + + /* post now if delay is zero */ + if ( delay_in_ms == 0 || player->set_mode.pcm_extraction) + { + debug_log("eos delay is zero. posting EOS now\n"); + MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL ); + + if ( player->set_mode.pcm_extraction ) + __mmplayer_cancel_eos_timer(player); + + return; + } + + /* cancel if existing */ + __mmplayer_cancel_eos_timer( player ); + + /* init new timeout */ + /* NOTE : consider give high priority to this timer */ + debug_log("posting EOS message after [%d] msec\n", delay_in_ms); + + player->eos_timer = g_timeout_add( delay_in_ms, + __mmplayer_eos_timer_cb, player ); + + player->context.global_default = g_main_context_default (); + debug_log("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer); + + /* check timer is valid. if not, send EOS now */ + if ( player->eos_timer == 0 ) + { + debug_warning("creating timer for delayed EOS has failed. sending EOS now\n"); + MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL ); + } +} + +static void +__mmplayer_cancel_eos_timer( mm_player_t* player ) +{ + return_if_fail( player ); + + if ( player->eos_timer ) + { + debug_log("cancel eos timer"); + __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer); + player->eos_timer = 0; + } + + return; +} + +static gboolean +__mmplayer_eos_timer_cb(gpointer u_data) +{ + mm_player_t* player = NULL; + player = (mm_player_t*) u_data; + + return_val_if_fail( player, FALSE ); + + if ( player->play_count > 1 ) + { + gint ret_value = 0; + ret_value = __gst_set_position( player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE); + if (ret_value == MM_ERROR_NONE) + { + MMHandleType attrs = 0; + attrs = MMPLAYER_GET_ATTRS(player); + + /* we successeded to rewind. update play count and then wait for next EOS */ + player->play_count--; + + mm_attrs_set_int_by_name(attrs, "profile_play_count", player->play_count); + mmf_attrs_commit ( attrs ); + } + else + { + debug_error("seeking to 0 failed in repeat play"); + } + } + else + { + /* posting eos */ + MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL ); + } + + /* we are returning FALSE as we need only one posting */ + return FALSE; +} + +static gboolean +__mmplayer_link_decoder( mm_player_t* player, GstPad *srcpad) +{ + const gchar* name = NULL; + GstStructure* str = NULL; + GstCaps* srccaps = NULL; + + MMPLAYER_FENTER(); + + return_val_if_fail( player, FALSE ); + return_val_if_fail ( srcpad, FALSE ); + + /* to check any of the decoder (video/audio) need to be linked to parser*/ + srccaps = gst_pad_query_caps( srcpad, NULL); + if ( !srccaps ) + goto ERROR; + + str = gst_caps_get_structure( srccaps, 0 ); + if ( ! str ) + goto ERROR; + + name = gst_structure_get_name(str); + if ( ! name ) + goto ERROR; + + if (strstr(name, "video")) + { + if(player->videodec_linked) + { + debug_msg("Video decoder already linked\n"); + return FALSE; + } + } + if (strstr(name, "audio")) + { + if(player->audiodec_linked) + { + debug_msg("Audio decoder already linked\n"); + return FALSE; + } + } + + gst_caps_unref( srccaps ); + + MMPLAYER_FLEAVE(); + + return TRUE; + +ERROR: + if ( srccaps ) + gst_caps_unref( srccaps ); + + return FALSE; +} + +static gboolean +__mmplayer_link_sink( mm_player_t* player , GstPad *srcpad) +{ + const gchar* name = NULL; + GstStructure* str = NULL; + GstCaps* srccaps = NULL; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, FALSE ); + return_val_if_fail ( srcpad, FALSE ); + + /* to check any of the decoder (video/audio) need to be linked to parser*/ + srccaps = gst_pad_query_caps( srcpad, NULL ); + if ( !srccaps ) + goto ERROR; + + str = gst_caps_get_structure( srccaps, 0 ); + if ( ! str ) + goto ERROR; + + name = gst_structure_get_name(str); + if ( ! name ) + goto ERROR; + + if (strstr(name, "video")) + { + if(player->videosink_linked) + { + debug_msg("Video Sink already linked\n"); + return FALSE; + } + } + if (strstr(name, "audio")) + { + if(player->audiosink_linked) + { + debug_msg("Audio Sink already linked\n"); + return FALSE; + } + } + if (strstr(name, "text")) + { + if(player->textsink_linked) + { + debug_msg("Text Sink already linked\n"); + return FALSE; + } + } + + gst_caps_unref( srccaps ); + + MMPLAYER_FLEAVE(); + + return TRUE; + //return (!player->videosink_linked || !player->audiosink_linked); + +ERROR: + if ( srccaps ) + gst_caps_unref( srccaps ); + + return FALSE; +} + + +/* sending event to one of sinkelements */ +static gboolean +__gst_send_event_to_sink( mm_player_t* player, GstEvent* event ) +{ + GstEvent * event2 = NULL; + GList *sinks = NULL; + gboolean res = FALSE; + MMPLAYER_FENTER(); + + return_val_if_fail( player, FALSE ); + return_val_if_fail ( event, FALSE ); + + if ( player->play_subtitle && !player->use_textoverlay) + event2 = gst_event_copy((const GstEvent *)event); + + sinks = player->sink_elements; + while (sinks) + { + GstElement *sink = GST_ELEMENT_CAST (sinks->data); + + if (GST_IS_ELEMENT(sink)) + { + /* keep ref to the event */ + gst_event_ref (event); + + if ( (res = gst_element_send_event (sink, event)) ) + { + debug_log("sending event[%s] to sink element [%s] success!\n", + GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink) ); + + /* rtsp case, asyn_done is not called after seek during pause state */ + if (MMPLAYER_IS_RTSP_STREAMING(player)) + { + if (strstr(GST_EVENT_TYPE_NAME(event), "seek")) + { + if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) + { + debug_log("RTSP seek completed, after pause state..\n"); + player->doing_seek = FALSE; + MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL ); + } + + } + } + + if( MMPLAYER_IS_ES_BUFF_SRC(player)) + { + sinks = g_list_next (sinks); + continue; + } + else + break; + } + + debug_log("sending event[%s] to sink element [%s] failed. try with next one.\n", + GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink) ); + } + + sinks = g_list_next (sinks); + } + +#if 0 + if (internal_sub) + request pad name = sink0; + else + request pad name = sink1; // external +#endif + + /* Note : Textbin is not linked to the video or audio bin. + * It needs to send the event to the text sink seperatelly. + */ + if ( player->play_subtitle && !player->use_textoverlay) + { + GstElement *text_sink = GST_ELEMENT_CAST (player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst); + + if (GST_IS_ELEMENT(text_sink)) + { + /* keep ref to the event */ + gst_event_ref (event2); + + if ((res = gst_element_send_event (text_sink, event2))) + { + debug_log("sending event[%s] to subtitle sink element [%s] success!\n", + GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink) ); + } + else + { + debug_error("sending event[%s] to subtitle sink element [%s] failed!\n", + GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink) ); + } + + gst_event_unref (event2); + } + } + + gst_event_unref (event); + + MMPLAYER_FLEAVE(); + + return res; +} + +static void +__mmplayer_add_sink( mm_player_t* player, GstElement* sink ) +{ + MMPLAYER_FENTER(); + + return_if_fail ( player ); + return_if_fail ( sink ); + + player->sink_elements = + g_list_append(player->sink_elements, sink); + + MMPLAYER_FLEAVE(); +} + +static void +__mmplayer_del_sink( mm_player_t* player, GstElement* sink ) +{ + MMPLAYER_FENTER(); + + return_if_fail ( player ); + return_if_fail ( sink ); + + player->sink_elements = + g_list_remove(player->sink_elements, sink); + + MMPLAYER_FLEAVE(); +} + +static gboolean +__gst_seek(mm_player_t* player, GstElement * element, gdouble rate, + GstFormat format, GstSeekFlags flags, GstSeekType cur_type, + gint64 cur, GstSeekType stop_type, gint64 stop ) +{ + GstEvent* event = NULL; + gboolean result = FALSE; + + MMPLAYER_FENTER(); + + return_val_if_fail( player, FALSE ); + + __mmplayer_drop_subtitle(player, FALSE); + + event = gst_event_new_seek (rate, format, flags, cur_type, + cur, stop_type, stop); + + result = __gst_send_event_to_sink( player, event ); + + MMPLAYER_FLEAVE(); + + return result; +} + +/* NOTE : be careful with calling this api. please refer to below glib comment + * glib comment : Note that there is a bug in GObject that makes this function much + * less useful than it might seem otherwise. Once gobject is disposed, the callback + * will no longer be called, but, the signal handler is not currently disconnected. + * If the instance is itself being freed at the same time than this doesn't matter, + * since the signal will automatically be removed, but if instance persists, + * then the signal handler will leak. You should not remove the signal yourself + * because in a future versions of GObject, the handler will automatically be + * disconnected. + * + * It's possible to work around this problem in a way that will continue to work + * with future versions of GObject by checking that the signal handler is still + * connected before disconnected it: + * + * if (g_signal_handler_is_connected (instance, id)) + * g_signal_handler_disconnect (instance, id); + */ +static void +__mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type) +{ + GList* sig_list = NULL; + MMPlayerSignalItem* item = NULL; + + MMPLAYER_FENTER(); + + return_if_fail( player ); + + debug_log("release signals type : %d", type); + + if ((type < MM_PLAYER_SIGNAL_TYPE_AUTOPLUG) || (type >= MM_PLAYER_SIGNAL_TYPE_ALL)) + { + __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG); + __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN); + __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN); + __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN); + __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_OTHERS); + return; + } + + sig_list = player->signals[type]; + + for ( ; sig_list; sig_list = sig_list->next ) + { + item = sig_list->data; + + if ( item && item->obj && GST_IS_ELEMENT(item->obj) ) + { + if ( g_signal_handler_is_connected ( item->obj, item->sig ) ) + { + g_signal_handler_disconnect ( item->obj, item->sig ); + } + } + + MMPLAYER_FREEIF( item ); + } + + g_list_free ( player->signals[type] ); + player->signals[type] = NULL; + + MMPLAYER_FLEAVE(); + + return; +} + +int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay) +{ + mm_player_t* player = 0; + int prev_display_surface_type = 0; + void *prev_display_overlay = NULL; + const gchar *klass = NULL; + gchar *cur_videosink_name = NULL; + int ret = 0; + int i = 0; + int num_of_dec = 2; /* DEC1, DEC2 */ + + MMPLAYER_FENTER(); + + return_val_if_fail(handle, MM_ERROR_COMMON_INVALID_ARGUMENT); + return_val_if_fail(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT); + + player = MM_PLAYER_CAST(handle); + + if (surface_type < MM_DISPLAY_SURFACE_X && surface_type >= MM_DISPLAY_SURFACE_NUM) + { + debug_error("Not support this surface type(%d) for changing vidoesink", surface_type); + MMPLAYER_FLEAVE(); + return MM_ERROR_INVALID_ARGUMENT; + } + + /* load previous attributes */ + if (player->attrs) + { + mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &prev_display_surface_type); + mm_attrs_get_data_by_name (player->attrs, "display_overlay", &prev_display_overlay); + debug_log("[0: X surface, 1: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type); + if (prev_display_surface_type == surface_type) + { + debug_log("incoming display surface type is same as previous one, do nothing.."); + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; + } + } + else + { + debug_error("failed to load attributes"); + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_INTERNAL; + } + + /* check videosink element is created */ + if (!player->pipeline || !player->pipeline->videobin || + !player->pipeline->videobin[MMPLAYER_V_SINK].gst ) + { + debug_log("videosink element is not yet ready"); + + /* videobin is not created yet, so we just set attributes related to display surface */ + debug_log("store display attribute for given surface type(%d)", surface_type); + mm_attrs_set_int_by_name (player->attrs, "display_surface_type", surface_type); + mm_attrs_set_data_by_name (player->attrs, "display_overlay", display_overlay, sizeof(display_overlay)); + if ( mmf_attrs_commit ( player->attrs ) ) + { + debug_error("failed to commit attribute"); + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_INTERNAL; + } + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; + } + else + { + /* get player command status */ + if ( !(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE) ) + { + debug_error("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command",player->cmd); + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_INVALID_STATE; + } + + /* get a current videosink name */ + cur_videosink_name = GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_SINK].gst); + + /* surface change */ + for ( i = 0 ; i < num_of_dec ; i++) + { + if ( player->pipeline->mainbin && + player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst ) + { + GstElementFactory *decfactory; + decfactory = gst_element_get_factory (player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst); + + klass = gst_element_factory_get_metadata (decfactory, GST_ELEMENT_METADATA_KLASS); + if ((g_strrstr(klass, "Codec/Decoder/Video"))) + { + if ( !strncmp(cur_videosink_name, "x", 1) && (surface_type == MM_DISPLAY_SURFACE_EVAS) ) + { + ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_evas, surface_type, display_overlay); + if (ret) + { + goto ERROR_CASE; + } + else + { + debug_warning("success to changing display surface(%d)",surface_type); + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; + } + } + else if (!strncmp(cur_videosink_name, "evas", 4) && (surface_type == MM_DISPLAY_SURFACE_X) ) + { + ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_x, surface_type, display_overlay); + if (ret) + { + goto ERROR_CASE; + } + else + { + debug_warning("success to changing display surface(%d)",surface_type); + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; + } + } + else + { + debug_error("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface",surface_type, cur_videosink_name); + ret = MM_ERROR_PLAYER_INTERNAL; + goto ERROR_CASE; + } + } + } + } + } + +ERROR_CASE: + /* rollback to previous attributes */ + mm_attrs_set_int_by_name (player->attrs, "display_surface_type", prev_display_surface_type); + mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*)); + if ( mmf_attrs_commit ( player->attrs ) ) + { + debug_error("failed to commit attributes to rollback"); + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_INTERNAL; + } + MMPLAYER_FLEAVE(); + return ret; +} + +/* NOTE : It does not support some use cases, eg using colorspace converter */ +int +__mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay) +{ + GstPad *src_pad_dec = NULL; + GstPad *sink_pad_videosink = NULL; + GstPad *sink_pad_videobin = NULL; + GstClock *clock = NULL; + MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM; + int ret = MM_ERROR_NONE; + gboolean is_audiobin_created = TRUE; + + MMPLAYER_FENTER(); + + return_val_if_fail(player, MM_ERROR_COMMON_INVALID_ARGUMENT); + return_val_if_fail(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT); + return_val_if_fail(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT); + + debug_log("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element); + debug_log("surface type(%d), display overlay(%x)", surface_type, display_overlay); + + /* get information whether if audiobin is created */ + if ( !player->pipeline->audiobin || + !player->pipeline->audiobin[MMPLAYER_A_SINK].gst ) + { + debug_warning("audiobin is null, this video content may not have audio data"); + is_audiobin_created = FALSE; + } + + /* get current state of player */ + previous_state = MMPLAYER_CURRENT_STATE(player); + debug_log("previous state(%d)", previous_state); + + + /* get src pad of decoder and block it */ + src_pad_dec = gst_element_get_static_pad (GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src"); + if (!src_pad_dec) + { + debug_error("failed to get src pad from decode in mainbin"); + return MM_ERROR_PLAYER_INTERNAL; + } + + if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) + { + debug_warning("trying to block pad(video)"); +// if (!gst_pad_set_blocked (src_pad_dec, TRUE)) + gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, + NULL, NULL, NULL); + + { + debug_error("failed to set block pad(video)"); + return MM_ERROR_PLAYER_INTERNAL; + } + debug_warning("pad is blocked(video)"); + } + else + { + /* no data flows, so no need to do pad_block */ + if (player->doing_seek) { + debug_warning("not completed seek(%d), do nothing", player->doing_seek); + } + debug_log("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)"); + } + + /* remove pad */ + if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, + GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) + { + debug_error("failed to remove previous ghost_pad for videobin"); + return MM_ERROR_PLAYER_INTERNAL; + } + + /* change state of videobin to NULL */ + debug_log("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL); + ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL); + if (ret != GST_STATE_CHANGE_SUCCESS) + { + debug_error("failed to change state of videobin to NULL"); + return MM_ERROR_PLAYER_INTERNAL; + } + + /* unlink between decoder and videobin and remove previous videosink from videobin */ + GST_ELEMENT_UNLINK(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst),GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst)); + if ( !gst_bin_remove (GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst)) ) + { + debug_error("failed to remove former videosink from videobin"); + return MM_ERROR_PLAYER_INTERNAL; + } + + __mmplayer_del_sink( player, player->pipeline->videobin[MMPLAYER_V_SINK].gst ); + + /* create a new videosink and add it to videobin */ + player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, videosink_element); + gst_bin_add (GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst)); + __mmplayer_add_sink( player, player->pipeline->videobin[MMPLAYER_V_SINK].gst ); + g_object_set (G_OBJECT (player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL); + + /* save attributes */ + if (player->attrs) + { + /* set a new display surface type */ + mm_attrs_set_int_by_name (player->attrs, "display_surface_type", surface_type); + /* set a new diplay overlay */ + switch (surface_type) + { + case MM_DISPLAY_SURFACE_X: + debug_log("save attributes related to display surface to X : xid = %d", *(int*)display_overlay); + mm_attrs_set_data_by_name (player->attrs, "display_overlay", display_overlay, sizeof(display_overlay)); + break; + case MM_DISPLAY_SURFACE_EVAS: + debug_log("save attributes related to display surface to EVAS : evas image object = %x", display_overlay); + mm_attrs_set_data_by_name (player->attrs, "display_overlay", display_overlay, sizeof(void*)); + break; + default: + debug_error("invalid type(%d) for changing display surface",surface_type); + MMPLAYER_FLEAVE(); + return MM_ERROR_INVALID_ARGUMENT; + } + if ( mmf_attrs_commit ( player->attrs ) ) + { + debug_error("failed to commit"); + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_INTERNAL; + } + } + else + { + debug_error("player->attrs is null, failed to save attributes"); + MMPLAYER_FLEAVE(); + return MM_ERROR_PLAYER_INTERNAL; + } + + /* update video param */ + if ( MM_ERROR_NONE != _mmplayer_update_video_param( player ) ) + { + debug_error("failed to update video param"); + return MM_ERROR_PLAYER_INTERNAL; + } + + /* change state of videobin to READY */ + debug_log("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY); + ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY); + if (ret != GST_STATE_CHANGE_SUCCESS) + { + debug_error("failed to change state of videobin to READY"); + return MM_ERROR_PLAYER_INTERNAL; + } + + /* change ghostpad */ + sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink"); + if ( !sink_pad_videosink ) + { + debug_error("failed to get sink pad from videosink element"); + return MM_ERROR_PLAYER_INTERNAL; + } + player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink); + if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) + { + debug_error("failed to set active to ghost_pad"); + return MM_ERROR_PLAYER_INTERNAL; + } + if ( FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin) ) + { + debug_error("failed to change ghostpad for videobin"); + return MM_ERROR_PLAYER_INTERNAL; + } + gst_object_unref(sink_pad_videosink); + + /* link decoder with videobin */ + sink_pad_videobin = gst_element_get_static_pad( GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink"); + if ( !sink_pad_videobin ) + { + debug_error("failed to get sink pad from videobin"); + return MM_ERROR_PLAYER_INTERNAL; + } + if ( GST_PAD_LINK_OK != GST_PAD_LINK(src_pad_dec, sink_pad_videobin) ) + { + debug_error("failed to link"); + return MM_ERROR_PLAYER_INTERNAL; + } + gst_object_unref(sink_pad_videobin); + + /* clock setting for a new videosink plugin */ + /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink, + so we set it from audiosink plugin or pipeline(system clock) */ + if (!is_audiobin_created) + { + debug_warning("audiobin is not created, get clock from pipeline.."); + clock = GST_ELEMENT_CLOCK (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst); + } + else + { + clock = GST_ELEMENT_CLOCK (player->pipeline->audiobin[MMPLAYER_A_SINK].gst); + } + if (clock) + { + GstClockTime now; + GstClockTime base_time; + debug_log("set the clock to videosink"); + gst_element_set_clock (GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock); + clock = GST_ELEMENT_CLOCK (player->pipeline->videobin[MMPLAYER_V_SINK].gst); + if (clock) + { + debug_log("got clock of videosink"); + now = gst_clock_get_time ( clock ); + base_time = GST_ELEMENT_CAST (player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time; + debug_log ("at time %" GST_TIME_FORMAT ", base %" + GST_TIME_FORMAT, GST_TIME_ARGS (now), GST_TIME_ARGS (base_time)); + } + else + { + debug_error("failed to get clock of videosink after setting clock"); + return MM_ERROR_PLAYER_INTERNAL; + } + } + else + { + debug_warning("failed to get clock, maybe it is the time before first playing"); + } + + if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) + { + /* change state of videobin to PAUSED */ + debug_log("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING); + ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING); + if (ret != GST_STATE_CHANGE_FAILURE) + { + debug_warning("change state of videobin to PLAYING, ret(%d)", ret); + } + else + { + debug_error("failed to change state of videobin to PLAYING"); + return MM_ERROR_PLAYER_INTERNAL; + } + + /* release blocked and unref src pad of video decoder */ + #if 0 + if (!gst_pad_set_blocked (src_pad_dec, FALSE)) + { + debug_error("failed to set pad blocked FALSE(video)"); + return MM_ERROR_PLAYER_INTERNAL; + } + #endif + debug_warning("pad is unblocked(video)"); + } + else + { + if (player->doing_seek) { + debug_warning("not completed seek(%d)", player->doing_seek); + } + /* change state of videobin to PAUSED */ + debug_log("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED); + ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED); + if (ret != GST_STATE_CHANGE_FAILURE) + { + debug_warning("change state of videobin to PAUSED, ret(%d)", ret); + } + else + { + debug_error("failed to change state of videobin to PLAYING"); + return MM_ERROR_PLAYER_INTERNAL; + } + + /* already skipped pad block */ + debug_log("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)"); + } + + /* do get/set position for new videosink plugin */ + { + unsigned long position = 0; + gint64 pos_msec = 0; + + debug_log("do get/set position for new videosink plugin"); + if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position )) + { + debug_error("failed to get position"); + return MM_ERROR_PLAYER_INTERNAL; + } +#ifdef SINKCHANGE_WITH_ACCURATE_SEEK + /* accurate seek */ + if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE )) + { + debug_error("failed to set position"); + return MM_ERROR_PLAYER_INTERNAL; + } +#else + /* key unit seek */ + pos_msec = position * G_GINT64_CONSTANT(1000000); + ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0, + GST_FORMAT_TIME, ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT ), + GST_SEEK_TYPE_SET, pos_msec, + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE ); + if ( !ret ) + { + debug_error("failed to set position"); + return MM_ERROR_PLAYER_INTERNAL; + } +#endif + } + + if (src_pad_dec) + { + gst_object_unref (src_pad_dec); + } + debug_log("success to change sink"); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + + +/* Note : if silent is true, then subtitle would not be displayed. :*/ +int _mmplayer_set_subtitle_silent (MMHandleType hplayer, int silent) +{ + mm_player_t* player = (mm_player_t*) hplayer; + + MMPLAYER_FENTER(); + + /* check player handle */ + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + player->set_mode.subtitle_off = silent; + + debug_log("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF"); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +int _mmplayer_remove_audio_parser_decoder(mm_player_t* player,GstPad *inpad) +{ + int result = MM_ERROR_NONE; + GstPad *peer = NULL,*pad = NULL; + GstElement *Element = NULL; + MMPlayerGstElement* mainbin = NULL; + mainbin = player->pipeline->mainbin; + + #if 0 + if(!gst_pad_set_blocked(inpad,TRUE)) + { + result = MM_ERROR_PLAYER_INTERNAL; + goto EXIT; + } + #endif + gst_pad_add_probe(inpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, + NULL, NULL, NULL); + + /*Getting pad connected to demuxer audio pad */ + peer = gst_pad_get_peer(inpad); + /* Disconnecting Demuxer and its peer plugin [audio] */ + if(peer) + { + if(!gst_pad_unlink(inpad,peer)) + { + result = MM_ERROR_PLAYER_INTERNAL; + goto EXIT; + } + } + else + { + result = MM_ERROR_PLAYER_INTERNAL; + goto EXIT; + } + /*Removing elements between Demuxer and audiobin*/ + while(peer != NULL) + { + gchar *Element_name = NULL; + gchar *factory_name = NULL; + GList *elements = NULL; + GstElementFactory *factory = NULL; + /*Getting peer element*/ + Element = gst_pad_get_parent_element(peer); + if(Element == NULL) + { + gst_object_unref(peer); + result = MM_ERROR_PLAYER_INTERNAL; + break; + } + + Element_name = gst_element_get_name(Element); + factory = gst_element_get_factory(Element); + /*checking the element is audio bin*/ + if(!strcmp(Element_name,"audiobin")) + { + gst_object_unref(peer); + result = MM_ERROR_NONE; + g_free(Element_name); + break; + } + factory_name = GST_OBJECT_NAME(factory); + pad = gst_element_get_static_pad(Element,"src"); + if(pad == NULL) + { + result = MM_ERROR_PLAYER_INTERNAL; + g_free(Element_name); + break; + } + gst_object_unref(peer); + peer = gst_pad_get_peer(pad); + if(peer) + { + if(!gst_pad_unlink(pad,peer)) + { + gst_object_unref(peer); + gst_object_unref(pad); + result = MM_ERROR_PLAYER_INTERNAL; + g_free(Element_name); + break; + } + } + elements = player->parsers; + /* Removing the element form the list*/ + for ( ; elements; elements = g_list_next(elements)) + { + Element_name = elements->data; + if(g_strrstr(Element_name,factory_name)) + { + player->parsers = g_list_remove(player->parsers,elements->data); + } + } + gst_element_set_state(Element,GST_STATE_NULL); + gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),Element); + gst_object_unref(pad); + if(Element == mainbin[MMPLAYER_M_Q1].gst) + { + mainbin[MMPLAYER_M_Q1].gst = NULL; + } + else if(Element == mainbin[MMPLAYER_M_Q2].gst) + { + mainbin[MMPLAYER_M_Q2].gst = NULL; + } + else if(Element == mainbin[MMPLAYER_M_DEC1].gst) + { + mainbin[MMPLAYER_M_DEC1].gst = NULL; + } + else if(Element == mainbin[MMPLAYER_M_DEC2].gst) + { + mainbin[MMPLAYER_M_DEC2].gst = NULL; + } + gst_object_unref(Element); + } +EXIT: + return result; +} + +int _mmplayer_sync_subtitle_pipeline(mm_player_t* player) +{ + MMPlayerGstElement* mainbin = NULL; + MMPlayerGstElement* textbin = NULL; + GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE; + GstState current_state = GST_STATE_VOID_PENDING; + GstState element_state = GST_STATE_VOID_PENDING; + GstState element_pending_state = GST_STATE_VOID_PENDING; + gint64 time = 0; + GstEvent *event = NULL; + int result = MM_ERROR_NONE; + + GstClock *curr_clock = NULL; + GstClockTime base_time, start_time, curr_time; + + + MMPLAYER_FENTER(); + + /* check player handle */ + return_val_if_fail ( player && player->pipeline , MM_ERROR_PLAYER_NOT_INITIALIZED); + + if (!(player->pipeline->mainbin) || !(player->pipeline->textbin)) + { + debug_error("Pipeline is not in proper state\n"); + result = MM_ERROR_PLAYER_NOT_INITIALIZED; + goto EXIT; + } + + mainbin = player->pipeline->mainbin; + textbin = player->pipeline->textbin; + + current_state = GST_STATE (mainbin[MMPLAYER_M_PIPE].gst); + + // sync clock with current pipeline + curr_clock = GST_ELEMENT_CLOCK (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst); + curr_time = gst_clock_get_time (curr_clock); + + base_time = gst_element_get_base_time (GST_ELEMENT_CAST (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)); + start_time = gst_element_get_start_time (GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)); + + debug_log ("base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT, + GST_TIME_ARGS (base_time), GST_TIME_ARGS (start_time), GST_TIME_ARGS (curr_time)); + + if (current_state > GST_STATE_READY) + { + // sync state with current pipeline + gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED); + gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED); + gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED); + + ret = gst_element_get_state (mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND); + if ( GST_STATE_CHANGE_FAILURE == ret ) + { + debug_error("fail to state change.\n"); + } + } + + gst_element_set_base_time (textbin[MMPLAYER_T_BIN].gst, base_time); + gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time); + + if (curr_clock) + { + gst_element_set_clock (textbin[MMPLAYER_T_BIN].gst, curr_clock); + gst_object_unref (curr_clock); + } + + // seek to current position + if (!gst_element_query_position (mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) + { + result = MM_ERROR_PLAYER_INVALID_STATE; + debug_error("gst_element_query_position failed, invalid state\n"); + goto EXIT; + } + + debug_log("seek time = %lld\n", time); + event = gst_event_new_seek (1.0, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1); + if (event) + { + __gst_send_event_to_sink(player, event); + } + else + { + result = MM_ERROR_PLAYER_INTERNAL; + debug_error("gst_event_new_seek failed\n"); + goto EXIT; + } + + // sync state with current pipeline + gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst); + gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst); + gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst); + +EXIT: + return result; +} + +static int +__mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE; + GstState current_state = GST_STATE_VOID_PENDING; + + MMHandleType attrs = 0; + MMPlayerGstElement* mainbin = NULL; + MMPlayerGstElement* textbin = NULL; + + gchar* subtitle_uri = NULL; + int result = MM_ERROR_NONE; + const gchar *charset = NULL; + + MMPLAYER_FENTER(); + + /* check player handle */ + return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + return_val_if_fail( filepath, MM_ERROR_COMMON_INVALID_ARGUMENT ); + + if (!(player->pipeline) || !(player->pipeline->mainbin)) + { + result = MM_ERROR_PLAYER_INVALID_STATE; + debug_error("Pipeline is not in proper state\n"); + goto EXIT; + } + + mainbin = player->pipeline->mainbin; + textbin = player->pipeline->textbin; + + current_state = GST_STATE (mainbin[MMPLAYER_M_PIPE].gst); + if (current_state < GST_STATE_READY) + { + result = MM_ERROR_PLAYER_INVALID_STATE; + debug_error("Pipeline is not in proper state\n"); + goto EXIT; + } + + attrs = MMPLAYER_GET_ATTRS(player); + if (!attrs) + { + debug_error("cannot get content attribute\n"); + result = MM_ERROR_PLAYER_INTERNAL; + goto EXIT; + } + + mm_attrs_get_string_by_name (attrs, "subtitle_uri", &subtitle_uri); + if (!subtitle_uri || strlen(subtitle_uri) < 1) + { + debug_error("subtitle uri is not proper filepath\n"); + result = MM_ERROR_PLAYER_INVALID_URI; + goto EXIT; + } + + debug_log("old subtitle file path is [%s]\n", subtitle_uri); + debug_log("new subtitle file path is [%s]\n", filepath); + + if (!strcmp (filepath, subtitle_uri)) + { + debug_log("No need to swtich subtitle, as input filepath is same as current filepath\n"); + goto EXIT; + } + else + { + mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath); + if (mmf_attrs_commit(player->attrs)) + { + debug_error("failed to commit.\n"); + goto EXIT; + } + } + + //gst_pad_set_blocked_async(src-srcpad, TRUE) + + ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY); + if (ret != GST_STATE_CHANGE_SUCCESS) + { + debug_error("failed to change state of textbin to READY"); + result = MM_ERROR_PLAYER_INTERNAL; + goto EXIT; + } + + ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY); + if (ret != GST_STATE_CHANGE_SUCCESS) + { + debug_error("failed to change state of subparse to READY"); + result = MM_ERROR_PLAYER_INTERNAL; + goto EXIT; + } + + ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY); + if (ret != GST_STATE_CHANGE_SUCCESS) + { + debug_error("failed to change state of filesrc to READY"); + result = MM_ERROR_PLAYER_INTERNAL; + goto EXIT; + } + + g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL); + + charset = util_get_charset(filepath); + if (charset) + { + debug_log ("detected charset is %s\n", charset ); + g_object_set (G_OBJECT (mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL); + } + + result = _mmplayer_sync_subtitle_pipeline(player); + +EXIT: + MMPLAYER_FLEAVE(); + return result; +} + +/* API to switch between external subtitles */ +int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath) +{ + int result = MM_ERROR_NONE; + mm_player_t* player = (mm_player_t*)hplayer; + + MMPLAYER_FENTER(); + + /* check player handle */ + return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + if (!player->pipeline) // IDLE state + { + mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath); + if (mmf_attrs_commit(player->attrs)) + { + debug_error("failed to commit.\n"); + result= MM_ERROR_PLAYER_INTERNAL; + } + } + else // curr state <> IDLE (READY, PAUSE, PLAYING..) + { + if ( filepath == NULL ) + return MM_ERROR_COMMON_INVALID_ARGUMENT; + + if (!__mmplayer_check_subtitle(player)) + { + mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath); + if (mmf_attrs_commit(player->attrs)) + { + debug_error("failed to commit.\n"); + result = MM_ERROR_PLAYER_INTERNAL; + } + + if ( MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player) ) + debug_error("fail to create subtitle src\n"); + + result = _mmplayer_sync_subtitle_pipeline(player); + } + else + { + result = __mmplayer_change_external_subtitle_language(player, filepath); + } + } + + MMPLAYER_FLEAVE(); + return result; +} + +static int +__mmplayer_change_selector_pad (mm_player_t* player, MMPlayerTrackType type, int index) +{ + int result = MM_ERROR_NONE; + gchar* change_pad_name = NULL; + GstPad* sinkpad = NULL; + MMPlayerGstElement* mainbin = NULL; + enum MainElementID elemId = MMPLAYER_M_NUM; + GstCaps* caps = NULL; + gint total_track_num = 0; + + MMPLAYER_FENTER(); + + return_val_if_fail (player && player->pipeline && player->pipeline->mainbin, + MM_ERROR_PLAYER_NOT_INITIALIZED); + + debug_log ("Change Track(%d) to %d\n", type, index); + + mainbin = player->pipeline->mainbin; + + if (type == MM_PLAYER_TRACK_TYPE_AUDIO) + { + elemId = MMPLAYER_M_A_INPUT_SELECTOR; + } + else if (type == MM_PLAYER_TRACK_TYPE_TEXT) + { + elemId = MMPLAYER_M_T_INPUT_SELECTOR; + } + else + { + debug_error ("Track Type Error\n"); + goto EXIT; + } + + if (mainbin[elemId].gst == NULL) + { + result = MM_ERROR_PLAYER_NO_OP; + debug_log ("Req track doesn't exist\n"); + goto EXIT; + } + + total_track_num = player->selector[type].total_track_num; + if (total_track_num <= 0) + { + result = MM_ERROR_PLAYER_NO_OP; + debug_log ("Language list is not available \n"); + goto EXIT; + } + + if ((index < 0) || (index >= total_track_num)) + { + result = MM_ERROR_INVALID_ARGUMENT; + debug_log ("Not a proper index : %d \n", index); + goto EXIT; + } + + /*To get the new pad from the selector*/ + change_pad_name = g_strdup_printf ("sink_%u", index); + if (change_pad_name == NULL) + { + result = MM_ERROR_PLAYER_INTERNAL; + debug_log ("Pad does not exists\n"); + goto EXIT; + } + + debug_log ("new active pad name: %s\n", change_pad_name); + + sinkpad = gst_element_get_static_pad (mainbin[elemId].gst, change_pad_name); + if (sinkpad == NULL) + { + debug_log ("sinkpad is NULL"); + result = MM_ERROR_PLAYER_INTERNAL; + goto EXIT; + } + + debug_log ("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad)); + g_object_set (mainbin[elemId].gst, "active-pad", sinkpad, NULL); + + caps = gst_pad_get_current_caps(sinkpad); + MMPLAYER_LOG_GST_CAPS_TYPE(caps); + + if (sinkpad) + gst_object_unref (sinkpad); + + if (type == MM_PLAYER_TRACK_TYPE_AUDIO) + { + __mmplayer_set_audio_attrs (player, caps); + } + +EXIT: + + MMPLAYER_FREEIF(change_pad_name); + return result; +} + +int _mmplayer_change_track_language (MMHandleType hplayer, MMPlayerTrackType type, int index) +{ + int result = MM_ERROR_NONE; + mm_player_t* player = NULL; + MMPlayerGstElement* mainbin = NULL; + + gint current_active_index = 0; + + GstState current_state = GST_STATE_VOID_PENDING; + GstEvent* event = NULL; + gint64 time = 0; + + MMPLAYER_FENTER(); + + player = (mm_player_t*)hplayer; + return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + if (!player->pipeline) + { + debug_error ("Track %d pre setting -> %d\n", type, index); + + player->selector[type].active_pad_index = index; + goto EXIT; + } + + mainbin = player->pipeline->mainbin; + + current_active_index = player->selector[type].active_pad_index; + + /*If index is same as running index no need to change the pad*/ + if (current_active_index == index) + { + goto EXIT; + } + + if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) + { + result = MM_ERROR_PLAYER_INVALID_STATE; + goto EXIT; + } + + current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst); + if (current_state < GST_STATE_PAUSED) + { + result = MM_ERROR_PLAYER_INVALID_STATE; + debug_warning ("Pipeline not in porper state\n"); + goto EXIT; + } + + result = __mmplayer_change_selector_pad(player, type, index); + if (result != MM_ERROR_NONE) + { + debug_error ("change selector pad error\n"); + goto EXIT; + } + + player->selector[type].active_pad_index = index; + + if (current_state == GST_STATE_PLAYING) + { + event = gst_event_new_seek (1.0, GST_FORMAT_TIME,(GstSeekFlags) (GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1); + if (event) + { + __gst_send_event_to_sink (player, event); + } + else + { + result = MM_ERROR_PLAYER_INTERNAL; + goto EXIT; + } + } + +EXIT: + return result; +} + +int _mmplayer_get_subtitle_silent (MMHandleType hplayer, int* silent) +{ + mm_player_t* player = (mm_player_t*) hplayer; + + MMPLAYER_FENTER(); + + /* check player handle */ + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + *silent = player->set_mode.subtitle_off; + + debug_log("subtitle is %s.\n", silent ? "ON" : "OFF"); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +gboolean +__is_es_buff_src( mm_player_t* player ) +{ + return_val_if_fail ( player, FALSE ); + + return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_ES_BUFF) ? TRUE : FALSE; +} + +gboolean +__has_suffix(mm_player_t* player, const gchar* suffix) +{ + return_val_if_fail( player, FALSE ); + return_val_if_fail( suffix, FALSE ); + + gboolean ret = FALSE; + gchar* t_url = g_ascii_strdown(player->profile.uri, -1); + gchar* t_suffix = g_ascii_strdown(suffix, -1); + + if ( g_str_has_suffix(player->profile.uri, suffix) ) + { + ret = TRUE; + } + + MMPLAYER_FREEIF(t_url); + MMPLAYER_FREEIF(t_suffix); + + return ret; +} + +int +_mmplayer_set_display_zoom(MMHandleType hplayer, float level, int x, int y) +{ + mm_player_t* player = (mm_player_t*) hplayer; + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + MMPLAYER_VIDEO_SINK_CHECK(player); + + debug_log("setting display zoom level = %f, offset = %d, %d", level, x, y); + + g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", level, "zoom-pos-x", x, "zoom-pos-y", y, NULL); + + return MM_ERROR_NONE; +} +int +_mmplayer_get_display_zoom(MMHandleType hplayer, float *level, int *x, int *y) +{ + + mm_player_t* player = (mm_player_t*) hplayer; + float _level = 0.0; + int _x = 0; + int _y = 0; + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + MMPLAYER_VIDEO_SINK_CHECK(player); + + g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", &_level, "zoom-pos-x", &_x, "zoom-pos-y", &_y, NULL); + + debug_log("display zoom level = %f, start off x = %d, y = %d", _level, _x, _y); + + *level = _level; + *x = _x; + *y = _y; + + return MM_ERROR_NONE; +} + +int +_mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode) +{ + mm_player_t* player = (mm_player_t*) hplayer; + + return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) + { + MMPLAYER_PRINT_STATE(player); + debug_error("wrong-state : can't set the download mode to parse"); + return MM_ERROR_PLAYER_INVALID_STATE; + } + + debug_log("set video hub download mode to %s", (mode)?"ON":"OFF"); + player->video_hub_download_mode = mode; + + return MM_ERROR_NONE; +} + +int +_mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable) +{ + mm_player_t* player = (mm_player_t*) hplayer; + + return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + debug_log("enable sync handler : %s", (enable)?"ON":"OFF"); + player->sync_handler = enable; + + return MM_ERROR_NONE; +} + +int +_mmplayer_use_system_clock (MMHandleType hplayer) +{ + mm_player_t* player = (mm_player_t*) hplayer; + + return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + debug_log("change clock provider to system"); + + // to use system clock + player->ini.provide_clock_for_movie = FALSE; + player->ini.provide_clock_for_music = FALSE; + + return MM_ERROR_NONE; +} + +int +_mmplayer_set_video_share_master_clock( MMHandleType hplayer, + long long clock, + long long clock_delta, + long long video_time, + long long media_clock, + long long audio_time) +{ + mm_player_t* player = (mm_player_t*) hplayer; + MMPlayerGstElement* mainbin = NULL; + GstClockTime start_time_audio = 0, start_time_video = 0; + GstClockTimeDiff base_time = 0, new_base_time = 0; + MMPlayerStateType current_state = MM_PLAYER_STATE_NONE; + gint64 api_delta = 0; + gint64 position = 0, position_delta = 0; + gint64 adj_base_time = 0; + GstClock *curr_clock = NULL; + GstClockTime curr_time = 0; + gboolean query_ret = TRUE; + int result = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail ( player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail ( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED); + + // debug_log("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time); + + if ((video_time < 0) || (player->doing_seek)) + { + debug_log("skip setting master clock. %lld", video_time); + goto EXIT; + } + + mainbin = player->pipeline->mainbin; + + curr_clock = gst_pipeline_get_clock (GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst)); + curr_time = gst_clock_get_time (curr_clock); + + current_state = MMPLAYER_CURRENT_STATE(player); + + if ( current_state == MM_PLAYER_STATE_PLAYING ) + query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position); + + if ( ( current_state != MM_PLAYER_STATE_PLAYING ) || + ( !query_ret )) + { + position = player->last_position; + debug_log ("query fail. %lld", position); + } + + clock*= GST_USECOND; + clock_delta *= GST_USECOND; + + api_delta = clock - curr_time; + if ((player->video_share_api_delta == 0 ) || (player->video_share_api_delta > api_delta)) + { + player->video_share_api_delta = api_delta; + } + else + { + clock_delta += (api_delta - player->video_share_api_delta); + } + + if ((player->video_share_clock_delta == 0 ) || (player->video_share_clock_delta > clock_delta)) + { + player->video_share_clock_delta = (gint64)clock_delta; + + position_delta = (position/GST_USECOND) - video_time; + position_delta *= GST_USECOND; + + adj_base_time = position_delta; + debug_log ("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time); + + } + else + { + gint64 new_play_time = 0; + gint64 network_delay =0; + + video_time *= GST_USECOND; + + network_delay = clock_delta - player->video_share_clock_delta; + new_play_time = video_time + network_delay; + + adj_base_time = position - new_play_time; + + debug_log ("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)", + network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay); + } + + /* Adjust Current Stream Time with base_time of sink + * 1. Set Start time to CLOCK NONE, to control the base time by MSL + * 2. Set new base time + * if adj_base_time is positive value, the stream time will be decreased. + * 3. If seek event is occurred, the start time will be reset. */ + if ((player->pipeline->audiobin) && + (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) + { + start_time_audio = gst_element_get_start_time (player->pipeline->audiobin[MMPLAYER_A_SINK].gst); + + if (start_time_audio != GST_CLOCK_TIME_NONE) + { + debug_log ("audio sink : gst_element_set_start_time -> NONE"); + gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE); + } + + base_time = gst_element_get_base_time (player->pipeline->audiobin[MMPLAYER_A_SINK].gst); + } + + if ((player->pipeline->videobin) && + (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) + { + start_time_video = gst_element_get_start_time (player->pipeline->videobin[MMPLAYER_V_SINK].gst); + + if (start_time_video != GST_CLOCK_TIME_NONE) + { + debug_log ("video sink : gst_element_set_start_time -> NONE"); + gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE); + } + + // if videobin exist, get base_time from videobin. + base_time = gst_element_get_base_time (player->pipeline->videobin[MMPLAYER_V_SINK].gst); + } + + new_base_time = base_time + adj_base_time; + + if ((player->pipeline->audiobin) && + (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) + gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time); + + if ((player->pipeline->videobin) && + (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) + gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time); + +EXIT: + MMPLAYER_FLEAVE(); + + return result; +} + +int +_mmplayer_get_video_share_master_clock( MMHandleType hplayer, + long long *video_time, + long long *media_clock, + long long *audio_time) +{ + mm_player_t* player = (mm_player_t*) hplayer; + MMPlayerGstElement* mainbin = NULL; + GstClock *curr_clock = NULL; + MMPlayerStateType current_state = MM_PLAYER_STATE_NONE; + gint64 position = 0; + gboolean query_ret = TRUE; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail ( player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail ( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED); + + return_val_if_fail ( video_time, MM_ERROR_COMMON_INVALID_ARGUMENT ); + return_val_if_fail ( media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT ); + return_val_if_fail ( audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT ); + + mainbin = player->pipeline->mainbin; + + curr_clock = gst_pipeline_get_clock (GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst)); + + current_state = MMPLAYER_CURRENT_STATE(player); + + if ( current_state != MM_PLAYER_STATE_PAUSED ) + query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position); + + if ( ( current_state == MM_PLAYER_STATE_PAUSED ) || + ( !query_ret )) + { + position = player->last_position; + } + + *media_clock = *video_time = *audio_time = (position/GST_USECOND); + + debug_log("media_clock: %lld, video_time: %lld (us)", *media_clock, *video_time); + + if (curr_clock) + gst_object_unref (curr_clock); + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +int +_mmplayer_get_video_rotate_angle(MMHandleType hplayer, int *angle) +{ + mm_player_t* player = (mm_player_t*) hplayer; + int org_angle = 0; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + return_val_if_fail ( angle, MM_ERROR_COMMON_INVALID_ARGUMENT ); + + if (player->v_stream_caps) + { + GstStructure *str = NULL; + + str = gst_caps_get_structure (player->v_stream_caps, 0); + if ( !gst_structure_get_int (str, "orientation", &org_angle)) + { + debug_log ("missing 'orientation' field in video caps"); + } + } + + debug_log("orientation: %d", org_angle); + *angle = org_angle; + + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; +} + +gboolean +__mmplayer_is_streaming(mm_player_t* player) +{ + gboolean result = FALSE; + + MMPLAYER_FENTER(); + + return_val_if_fail (player, FALSE); + result = __is_streaming (player) ; + + MMPLAYER_FLEAVE(); + return result; +} + +static gboolean +__mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element) +{ + return_val_if_fail (player, FALSE); + return_val_if_fail (element, FALSE); + + gchar *factory_name = GST_OBJECT_NAME (gst_element_get_factory(element)); + gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2]; + + int idx = 0; + + for ( idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++ ) + { + if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) + { + debug_log("dump [%s] sink pad", player->ini.dump_element_keyword[idx]); + mm_player_dump_t *dump_s; + dump_s = g_malloc (sizeof(mm_player_dump_t)); + + if (dump_s == NULL) + { + debug_error ("malloc fail"); + return FALSE; + } + + dump_s->dump_element_file = NULL; + dump_s->dump_pad = NULL; + dump_s->dump_pad = gst_element_get_static_pad (element, "sink"); + + if (dump_s->dump_pad) + { + memset (dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2); + sprintf (dump_file_name, "%s/%s_sink_pad.dump", player->ini.dump_element_path, player->ini.dump_element_keyword[idx]); + dump_s->dump_element_file = fopen(dump_file_name,"w+"); + dump_s->probe_handle_id = gst_pad_add_probe (dump_s->dump_pad, GST_PAD_PROBE_TYPE_BUFFER, __mmplayer_dump_buffer_probe_cb, dump_s->dump_element_file, NULL); + /* add list for removed buffer probe and close FILE */ + player->dump_list = g_list_append (player->dump_list, dump_s); + debug_log ("%s sink pad added buffer probe for dump", factory_name); + return TRUE; + } + else + { + g_free(dump_s); + dump_s = NULL; + debug_error ("failed to get %s sink pad added", factory_name); + } + + + } + } + return FALSE; +} + +static GstPadProbeReturn +__mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data) +{ + FILE *dump_data = (FILE *) u_data; +// int written = 0; + GstBuffer *buffer = gst_pad_probe_info_get_buffer(info); + GstMapInfo probe_info = GST_MAP_INFO_INIT; + + return_val_if_fail ( dump_data, FALSE ); + + gst_buffer_map(buffer, &probe_info, GST_MAP_READ); + +// debug_log ("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS( GST_BUFFER_TIMESTAMP(buffer))); + + fwrite ( probe_info.data, 1, probe_info.size , dump_data); + + return GST_PAD_PROBE_OK; +} + +static void +__mmplayer_release_dump_list (GList *dump_list) +{ + if (dump_list) + { + GList *d_list = dump_list; + for ( ;d_list ; d_list = g_list_next(d_list)) + { + mm_player_dump_t *dump_s = d_list->data; + if (dump_s->dump_pad) + { + if (dump_s->probe_handle_id) + { + gst_pad_remove_probe (dump_s->dump_pad, dump_s->probe_handle_id); + } + + } + if (dump_s->dump_element_file) + { + fclose(dump_s->dump_element_file); + dump_s->dump_element_file = NULL; + } + MMPLAYER_FREEIF(dump_s); + } + g_list_free(dump_list); + dump_list = NULL; + } +} + +int +_mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist) +{ + mm_player_t* player = (mm_player_t*) hplayer; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + return_val_if_fail ( exist, MM_ERROR_INVALID_ARGUMENT ); + + *exist = player->has_closed_caption; + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +int +_mmplayer_enable_media_packet_video_stream(MMHandleType hplayer, bool enable) +{ + mm_player_t* player = (mm_player_t*) hplayer; + + MMPLAYER_FENTER(); + + return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail (enable == TRUE || enable == FALSE, MM_ERROR_INVALID_ARGUMENT); + if(enable) + player->bufmgr = tbm_bufmgr_init(-1); + else { + tbm_bufmgr_deinit(player->bufmgr); + player->bufmgr = NULL; + } + + player->set_mode.media_packet_video_stream = enable; + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +void * _mm_player_media_packet_video_stream_internal_buffer_ref(void *buffer) +{ + void * ret = NULL + MMPLAYER_FENTER(); + /* increase ref count of gst buffer */ + if (buffer) + ret = gst_buffer_ref((GstBuffer *)buffer); + + MMPLAYER_FLEAVE(); + return ret; +} + +void _mm_player_media_packet_video_stream_internal_buffer_unref(void *buffer) +{ + MMPLAYER_FENTER(); + if (buffer) { + gst_buffer_unref((GstBuffer *)buffer); + buffer = NULL; + } + MMPLAYER_FLEAVE(); +} + +void +__gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data) +{ + mm_player_t *player = (mm_player_t*)user_data; + MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO; + + return_if_fail ( player ); + + debug_msg("app-src: feed audio\n"); + + if (player->media_stream_buffer_status_cb[type]) + { + player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, player->buffer_cb_user_param); + } +} + +void +__gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data) +{ + mm_player_t *player = (mm_player_t*)user_data; + MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO; + + return_if_fail ( player ); + + debug_msg("app-src: feed video\n"); + + if (player->media_stream_buffer_status_cb[type]) + { + player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, player->buffer_cb_user_param); + } +} + +void +__gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data) +{ + mm_player_t *player = (mm_player_t*)user_data; + MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT; + + return_if_fail ( player ); + + debug_msg("app-src: feed subtitle\n"); + + if (player->media_stream_buffer_status_cb[type]) + { + player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, player->buffer_cb_user_param); + } +} + +void +__gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data) +{ + mm_player_t *player = (mm_player_t*)user_data; + MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO; + + return_if_fail ( player ); + + debug_msg("app-src: audio buffer is full.\n"); + + if (player->media_stream_buffer_status_cb[type]) + { + player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, player->buffer_cb_user_param); + } +} + +void +__gst_appsrc_enough_video_data(GstElement *element, gpointer user_data) +{ + mm_player_t *player = (mm_player_t*)user_data; + MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO; + + return_if_fail ( player ); + + debug_msg("app-src: video buffer is full.\n"); + + if (player->media_stream_buffer_status_cb[type]) + { + player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, player->buffer_cb_user_param); + } +} + +gboolean +__gst_seek_audio_data (GstElement * appsrc, guint64 position, gpointer user_data) +{ + mm_player_t *player = (mm_player_t*)user_data; + MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO; + + return_val_if_fail( player, FALSE ); + + debug_log("app-src: seek audio data\n"); + + if (player->media_stream_seek_data_cb[type]) + { + player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param); + } + + return TRUE; +} + +gboolean +__gst_seek_video_data (GstElement * appsrc, guint64 position, gpointer user_data) +{ + mm_player_t *player = (mm_player_t*)user_data; + MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO; + + return_val_if_fail( player, FALSE ); + + debug_log("app-src: seek video data\n"); + + if (player->media_stream_seek_data_cb[type]) + { + player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param); + } + + return TRUE; +} + +gboolean +__gst_seek_subtitle_data (GstElement * appsrc, guint64 position, gpointer user_data) +{ + mm_player_t *player = (mm_player_t*)user_data; + MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT; + + return_val_if_fail( player, FALSE ); + + debug_log("app-src: seek subtitle data\n"); + + if (player->media_stream_seek_data_cb[type]) + { + player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param); + } + + return TRUE; +} + +int +_mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel) +{ + mm_player_t* player = (mm_player_t*) hplayer; + + MMPLAYER_FENTER(); + + return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); + + player->pcm_samplerate = samplerate; + player->pcm_channel = channel; + + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; +} + +int _mmplayer_get_raw_video_caps(mm_player_t *player, char **caps) +{ + GstCaps *v_caps = NULL; + GstPad *pad = NULL; + GstElement *gst; + gint stype = 0; + + if(!player->videosink_linked) { + debug_log("No video sink"); + return MM_ERROR_NONE; + } + mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype); + + if (stype == MM_DISPLAY_SURFACE_NULL) { + debug_log("Display type is NULL"); + if(!player->video_fakesink) { + debug_error("No fakesink"); + return MM_ERROR_PLAYER_INVALID_STATE; + } + gst = player->video_fakesink; + } + else { + if ( !player->pipeline || !player->pipeline->videobin || + !player->pipeline->videobin[MMPLAYER_V_SINK].gst ) { + debug_error("No video pipeline"); + return MM_ERROR_PLAYER_INVALID_STATE; + } + gst = player->pipeline->videobin[MMPLAYER_V_SINK].gst; + } + pad = gst_element_get_static_pad(gst, "sink"); + if(!pad) { + debug_error("static pad is NULL"); + return MM_ERROR_PLAYER_INVALID_STATE; + } + v_caps = gst_pad_get_current_caps(pad); + gst_object_unref( pad ); + + if(!v_caps) { + debug_error("fail to get caps"); + return MM_ERROR_PLAYER_INVALID_STATE; + } + + *caps = gst_caps_to_string(v_caps); + + gst_caps_unref(v_caps); + + return MM_ERROR_NONE; +} diff --git a/src/server/mm_player_sound_focus.c b/src/server/mm_player_sound_focus.c new file mode 100644 index 0000000..e9f2818 --- /dev/null +++ b/src/server/mm_player_sound_focus.c @@ -0,0 +1,295 @@ +/* + * libmm-player + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , YeJin Cho , + * Seungbae Shin , YoungHwan An + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include + +#include "mm_player_utils.h" +#include "mm_player_priv.h" +#include "mm_player_sound_focus.h" + +#define MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(x_player_sound_focus) \ +do \ +{ \ + if (!x_player_sound_focus) \ + { \ + debug_log("no sound focus instance");\ + return MM_ERROR_SOUND_NOT_INITIALIZED; \ + } \ +}while(0); + +void __mmplayer_sound_signal_callback (mm_sound_signal_name_t signal, int value, void *user_data) +{ + MMPlayerSoundFocus *sound_focus = (MMPlayerSoundFocus*)user_data; + + debug_log("sound signal callback %d / %d", signal, value); + + if (signal == MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS) + { + if (value == 1) + { + if (sound_focus->watch_id > 0) + { + debug_log("unset the focus watch cb"); + + mm_sound_unset_focus_watch_callback(sound_focus->watch_id); + sound_focus->watch_id = 0; + /* + if (sound_focus->subscribe_id > 0) + mm_sound_unsubscribe_signal(sound_focus->subscribe_id); + */ + } + } + } +} + +const gchar * +__mmplayer_sound_get_stream_type(gint type) +{ + switch ( type ) + { + case MM_SESSION_TYPE_CALL: + case MM_SESSION_TYPE_VIDEOCALL: + case MM_SESSION_TYPE_VOIP: + return "ringtone-voip"; + case MM_SESSION_TYPE_MEDIA: + return "media"; + case MM_SESSION_TYPE_NOTIFY: + return "notification"; + case MM_SESSION_TYPE_ALARM: + return "alarm"; + case MM_SESSION_TYPE_EMERGENCY: + return "emergency"; + default: + debug_warning("unexpected case!\n"); + return "media"; + } + + return "media"; +} + +int +_mmplayer_sound_acquire_focus(MMPlayerSoundFocus* sound_focus) +{ + int ret = MM_ERROR_NONE; + const gchar *stream_type = NULL; + + MMPLAYER_FENTER(); + MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus); + + if (sound_focus->acquired) + { + debug_warning("focus is already acquired. can't acquire again."); + return MM_ERROR_NONE; + } + + stream_type = __mmplayer_sound_get_stream_type(sound_focus->session_type); + + if ((!strstr(stream_type, "media")) || + (sound_focus->session_flags & MM_SESSION_OPTION_PAUSE_OTHERS)) + { + + ret = mm_sound_acquire_focus(sound_focus->focus_id, FOCUS_FOR_BOTH, NULL); + if (ret != MM_ERROR_NONE) + { + debug_error("failed to acquire sound focus\n"); + return ret; + } + + sound_focus->acquired = TRUE; + } + + MMPLAYER_FLEAVE(); + return ret; +} + +int +_mmplayer_sound_release_focus(MMPlayerSoundFocus* sound_focus) +{ + int ret = MM_ERROR_NONE; + const gchar *stream_type = NULL; + + MMPLAYER_FENTER(); + MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus); + + if (!sound_focus->acquired) + { + debug_warning("focus is not acquired. no need to release."); + return MM_ERROR_NONE; + } + + stream_type = __mmplayer_sound_get_stream_type(sound_focus->session_type); + + if ((!strstr(stream_type, "media")) || + (sound_focus->session_flags & MM_SESSION_OPTION_PAUSE_OTHERS)) + { + ret = mm_sound_release_focus(sound_focus->focus_id, FOCUS_FOR_BOTH, NULL); + if (ret != MM_ERROR_NONE) + { + debug_error("failed to release sound focus\n"); + return ret; + } + + sound_focus->acquired = FALSE; + } + + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; +} + +gint +_mmplayer_sound_register(MMPlayerSoundFocus* sound_focus, + mm_sound_focus_changed_cb focus_cb, mm_sound_focus_changed_watch_cb watch_cb, void* param) +{ + gint pid = -1; + gint ret = MM_ERROR_NONE; + const gchar *stream_type = NULL; + + MMPLAYER_FENTER(); + MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus); + + /* check if it's running on the media_server */ + if (sound_focus->pid > 0) + { + pid = sound_focus->pid; + debug_log("mm-player is running on different process. Just faking pid to [%d]. :-p\n", pid); + } + + /* read session information */ + ret = _mm_session_util_read_information(pid, &sound_focus->session_type, &sound_focus->session_flags); + if (ret != MM_ERROR_NONE) + { + debug_error("Read Session Type failed. ret:0x%X \n", ret); + + if (ret == MM_ERROR_INVALID_HANDLE) + { + int sig_value = 0; + + mm_sound_get_signal_value(MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS, &sig_value); + debug_warning("internal focus signal value=%d, id=%d\n", sig_value, sound_focus->subscribe_id); + + if ((sig_value == 0) && (sound_focus->subscribe_id == 0)) + { + ret = mm_sound_subscribe_signal(MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS, &sound_focus->subscribe_id, + (mm_sound_signal_callback)__mmplayer_sound_signal_callback, (void*)sound_focus); + if (ret != MM_ERROR_NONE) + { + debug_error("mm_sound_subscribe_signal is failed\n"); + return MM_ERROR_POLICY_BLOCKED; + } + + debug_log("register focus watch callback for the value is 0, sub_cb id %d\n", sound_focus->subscribe_id); + + ret = mm_sound_set_focus_watch_callback(FOCUS_FOR_BOTH, watch_cb, (void*)param, &sound_focus->watch_id); + if (ret != MM_ERROR_NONE) + { + debug_error("mm_sound_set_focus_watch_callback is failed\n"); + return MM_ERROR_POLICY_BLOCKED; + } + } + + return MM_ERROR_NONE; + } + else + { + return MM_ERROR_POLICY_BLOCKED; + } + } + + /* interpret session information */ + stream_type = __mmplayer_sound_get_stream_type(sound_focus->session_type); + debug_log("fid [%d] wid [%d] type[%s], flags[0x%02X]\n", + sound_focus->focus_id, sound_focus->watch_id, stream_type, sound_focus->session_flags); + + if (sound_focus->focus_id == 0) + { + /* get unique id */ + ret = mm_sound_focus_get_id(&sound_focus->focus_id); + if (ret != MM_ERROR_NONE) + { + debug_error("failed to get unique focus id\n"); + return MM_ERROR_POLICY_BLOCKED; + } + + /* register sound focus callback */ + ret = mm_sound_register_focus(sound_focus->focus_id, stream_type, focus_cb, (void*)param); + if (ret != MM_ERROR_NONE) + { + debug_error("mm_sound_register_focus is failed\n"); + return MM_ERROR_POLICY_BLOCKED; + } + } + + if ((sound_focus->watch_id == 0) && + (strstr(stream_type, "media")) && + !(sound_focus->session_flags & ASM_SESSION_OPTION_PAUSE_OTHERS) && + !(sound_focus->session_flags & ASM_SESSION_OPTION_UNINTERRUPTIBLE)) + { + debug_log("register focus watch callback\n"); + + ret = mm_sound_set_focus_watch_callback(FOCUS_FOR_BOTH, watch_cb, (void*)param, &sound_focus->watch_id); + if (ret != MM_ERROR_NONE) + { + debug_error("mm_sound_set_focus_watch_callback is failed\n"); + return MM_ERROR_POLICY_BLOCKED; + } + } + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + +gint +_mmplayer_sound_unregister(MMPlayerSoundFocus* sound_focus) +{ + MMPLAYER_FENTER(); + + MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus); + + debug_log("unregister sound focus callback\n"); + + if (sound_focus->focus_id > 0) + { + mm_sound_unregister_focus(sound_focus->focus_id); + sound_focus->focus_id = 0; + } + + if (sound_focus->watch_id > 0) + { + mm_sound_unset_focus_watch_callback(sound_focus->watch_id); + sound_focus->watch_id = 0; + } + + if (sound_focus->subscribe_id > 0) + { + mm_sound_unsubscribe_signal(sound_focus->subscribe_id); + sound_focus->subscribe_id = 0; + } + + MMPLAYER_FLEAVE(); + + return MM_ERROR_NONE; +} + diff --git a/src/server/mm_player_streaming.c b/src/server/mm_player_streaming.c new file mode 100644 index 0000000..151ce8b --- /dev/null +++ b/src/server/mm_player_streaming.c @@ -0,0 +1,1115 @@ +/* + * libmm-player + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , YeJin Cho , + * Seungbae Shin , YoungHwan An + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include "mm_player_utils.h" +#include "mm_player_streaming.h" + +#define TO_THE_END 0 + +typedef struct{ + gint byte_in_rate; // byte + gint byte_out_rate; // byte + gdouble time_rate; // second + guint buffer_criteria; // byte +}streaming_bitrate_info_t; + +typedef struct{ + gint64 position; // ns + gint64 duration; // ns + guint64 content_size; // bytes +}streaming_content_info_t; + +typedef struct{ + guint buffering_bytes; // bytes + gdouble buffering_time; // second + gdouble percent_byte; + gdouble percent_time; +}streaming_buffer_info_t; + +static void streaming_check_buffer_percent(gdouble in_low, gdouble in_high, gdouble *out_low, gdouble *out_high); +static void streaming_set_buffer_percent(mm_player_streaming_t* streamer, BufferType type, gdouble low_percent, gdouble high_percent_byte, gdouble high_percent_time); +static void streaming_set_queue2_queue_type (mm_player_streaming_t* streamer, gboolean use_file, gchar * file_path, guint64 content_size); +static void streaming_set_buffer_size(mm_player_streaming_t* streamer, BufferType type, guint buffering_bytes, gdouble buffering_time); +static void streaming_update_buffering_status(mm_player_streaming_t* streamer, GstMessage *buffering_msg, gint64 position); +static void streaming_get_current_bitrate_info( mm_player_streaming_t* streamer, + GstMessage *buffering_msg, + streaming_content_info_t content_info, + streaming_bitrate_info_t* bitrate_info); +static void +streaming_handle_fixed_buffering_mode( mm_player_streaming_t* streamer, + gint byte_out_rate, + gdouble fixed_buffering_time, + streaming_buffer_info_t* buffer_info); +static void +streaming_handle_adaptive_buffering_mode( mm_player_streaming_t* streamer, + streaming_content_info_t content_info, + streaming_bitrate_info_t bitrate_info, + streaming_buffer_info_t* buffer_info, + gint expected_play_time); +static void +streaming_update_buffer_setting ( mm_player_streaming_t* streamer, + GstMessage *buffering_msg, + guint64 content_size, + gint64 position, + gint64 duration); + +mm_player_streaming_t * +__mm_player_streaming_create (void) +{ + mm_player_streaming_t *streamer = NULL; + + MMPLAYER_FENTER(); + + streamer = (mm_player_streaming_t *) malloc (sizeof (mm_player_streaming_t)); + if (!streamer) + { + debug_error ("fail to create streaming player handle..\n"); + return NULL; + } + + memset(streamer, 0, sizeof(mm_player_streaming_t)); + + MMPLAYER_FLEAVE(); + + return streamer; +} + +static void +streaming_buffer_initialize (streaming_buffer_t* buffer_handle, gboolean buffer_init) +{ + if (buffer_init) + buffer_handle->buffer = NULL; + + buffer_handle->buffering_bytes = DEFAULT_BUFFER_SIZE_BYTES; + buffer_handle->buffering_time = DEFAULT_BUFFERING_TIME; + buffer_handle->buffer_low_percent = DEFAULT_BUFFER_LOW_PERCENT; + buffer_handle->buffer_high_percent = DEFAULT_BUFFER_HIGH_PERCENT; + buffer_handle->is_live = FALSE; + +} + +void __mm_player_streaming_initialize (mm_player_streaming_t* streamer) +{ + MMPLAYER_FENTER(); + + streamer->streaming_buffer_type = BUFFER_TYPE_DEFAULT; // multi-queue + + streaming_buffer_initialize(&(streamer->buffer_handle[BUFFER_TYPE_MUXED]), TRUE); + streaming_buffer_initialize(&(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]), TRUE); + + streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_ADAPTIVE; + streamer->buffering_req.is_pre_buffering = FALSE; + streamer->buffering_req.initial_second = 0; + streamer->buffering_req.runtime_second = 0; + + streamer->default_val.buffering_monitor = FALSE; + streamer->default_val.buffering_time = DEFAULT_BUFFERING_TIME; + + streamer->buffer_avg_bitrate = 0; + streamer->buffer_max_bitrate = 0; + streamer->need_update = FALSE; + streamer->need_sync = FALSE; + + streamer->is_buffering = FALSE; + streamer->is_buffering_done = FALSE; + streamer->is_adaptive_streaming = FALSE; + streamer->buffering_percent = -1; + + MMPLAYER_FLEAVE(); + return; +} + +void __mm_player_streaming_deinitialize (mm_player_streaming_t* streamer) +{ + MMPLAYER_FENTER(); + return_if_fail(streamer); + + streamer->streaming_buffer_type = BUFFER_TYPE_DEFAULT; // multi-queue + + streaming_buffer_initialize(&(streamer->buffer_handle[BUFFER_TYPE_MUXED]), FALSE); + streaming_buffer_initialize(&(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]), FALSE); + + streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_ADAPTIVE; + streamer->buffering_req.is_pre_buffering = FALSE; + streamer->buffering_req.initial_second = 0; + streamer->buffering_req.runtime_second = 0; + + streamer->default_val.buffering_monitor = FALSE; + streamer->default_val.buffering_time = DEFAULT_BUFFERING_TIME; + + streamer->buffer_avg_bitrate = 0; + streamer->buffer_max_bitrate = 0; + streamer->need_update = FALSE; + streamer->need_sync = FALSE; + + streamer->is_buffering = FALSE; + streamer->is_buffering_done = FALSE; + streamer->is_adaptive_streaming = FALSE; + + streamer->buffering_percent = -1; + + MMPLAYER_FLEAVE(); + return; +} + +void __mm_player_streaming_destroy (mm_player_streaming_t* streamer) +{ + MMPLAYER_FENTER(); + + if(streamer) + { + g_free (streamer); + streamer = NULL; + } + + MMPLAYER_FLEAVE(); + + return; +} + +void __mm_player_streaming_set_content_bitrate(mm_player_streaming_t* streamer, guint max_bitrate, guint avg_bitrate) +{ + MMPLAYER_FENTER(); + + return_if_fail(streamer); + + /* Note : Update buffering criterion bytes + * 1. maximum bitrate is considered first. + * 2. average bitrage * 3 is next. + * 3. if there are no updated bitrate, use default buffering limit. + */ + if (max_bitrate > 0 && streamer->buffer_max_bitrate != max_bitrate) + { + debug_log("set maximum bitrate(%dbps).\n", max_bitrate); + streamer->buffer_max_bitrate = max_bitrate; + if (streamer->buffering_req.is_pre_buffering == FALSE) + { + streamer->need_update = TRUE; + } + else + { + debug_log("pre-buffering...\n"); + + if (IS_MUXED_BUFFERING_MODE(streamer)) + streaming_update_buffer_setting(streamer, NULL, 0, 0, 0); + } + } + + if (avg_bitrate > 0 && streamer->buffer_avg_bitrate != avg_bitrate) + { + debug_log("set averate bitrate(%dbps).\n", avg_bitrate); + streamer->buffer_avg_bitrate = avg_bitrate; + + if (streamer->buffering_req.is_pre_buffering == FALSE) + { + streamer->need_update = TRUE; + } + else + { + debug_log("pre-buffering...\n"); + + if (IS_MUXED_BUFFERING_MODE(streamer)) + streaming_update_buffer_setting(streamer, NULL, 0, 0, 0); + } + } + + MMPLAYER_FLEAVE(); + return; +} + +static void +streaming_check_buffer_percent(gdouble in_low, gdouble in_high, gdouble *out_low, gdouble *out_high) +{ + gdouble buffer_low_percent = DEFAULT_BUFFER_LOW_PERCENT; + gdouble buffer_high_percent = DEFAULT_BUFFER_HIGH_PERCENT; + + MMPLAYER_FENTER(); + + return_if_fail(out_low && out_high); + + if (in_low <= MIN_BUFFER_PERCENT || in_low >= MAX_BUFFER_PERCENT) + { + debug_warning("buffer low percent is out of range. use defaut value."); + } + else + { + buffer_low_percent = in_low; + } + + if (in_high <= MIN_BUFFER_PERCENT || in_high >= MAX_BUFFER_PERCENT) + { + debug_warning("buffer high percent is out of range. use defaut value."); + } + else + { + buffer_high_percent = in_high; + } + + if (buffer_high_percent <= buffer_low_percent) + buffer_high_percent = buffer_low_percent + 1.0; + + debug_log("set buffer percent to %2.3f ~ %2.3f.", buffer_low_percent, buffer_high_percent); + + *out_low = buffer_low_percent; + *out_high = buffer_high_percent; +} + +static void +streaming_set_buffer_percent( mm_player_streaming_t* streamer, + BufferType type, + gdouble low_percent, + gdouble high_percent_byte, + gdouble high_percent_time) +{ + gdouble confirmed_low = DEFAULT_BUFFER_LOW_PERCENT; + gdouble confirmed_high = DEFAULT_BUFFER_HIGH_PERCENT; + gdouble high_percent = 0.0; + + streaming_buffer_t* buffer_handle = NULL; + gchar* factory_name = NULL; + + MMPLAYER_FENTER(); + return_if_fail(streamer); + return_if_fail(type < BUFFER_TYPE_MAX); + + buffer_handle = &(streamer->buffer_handle[type]); + if (!(buffer_handle && buffer_handle->buffer)) + { + debug_error("buffer_handle->buffer is NULL!"); + return; + } + + factory_name = GST_OBJECT_NAME(gst_element_get_factory(buffer_handle->buffer)); + + if (!factory_name) + { + debug_error("Fail to get factory name!"); + return; + } + + if (type == BUFFER_TYPE_MUXED) + high_percent = high_percent_byte; + else + high_percent = MAX(high_percent_time, high_percent_byte); + + streaming_check_buffer_percent(low_percent, high_percent, &confirmed_low, &confirmed_high); + + /* if use-buffering is disabled, this settings do not have any meaning. */ + debug_log("target buffer elem : %s (%2.3f ~ %2.3f)", + GST_ELEMENT_NAME(buffer_handle->buffer), confirmed_low, confirmed_high); + + if ((confirmed_low == DEFAULT_BUFFER_LOW_PERCENT) || + (buffer_handle->buffer_low_percent != confirmed_low)) + { + g_object_set (G_OBJECT(buffer_handle->buffer), "low-percent", (gint)confirmed_low, NULL); + } + + if ((confirmed_high == DEFAULT_BUFFER_HIGH_PERCENT) || + (buffer_handle->buffer_high_percent != confirmed_high)) + { + g_object_set (G_OBJECT(buffer_handle->buffer), "high-percent", (gint)confirmed_high, NULL); + } + + buffer_handle->buffer_low_percent = confirmed_low; + buffer_handle->buffer_high_percent = confirmed_high; + + MMPLAYER_FLEAVE(); + return; +} + +static void +streaming_set_queue2_queue_type (mm_player_streaming_t* streamer, gboolean use_file, gchar * file_path, guint64 content_size) +{ + streaming_buffer_t* buffer_handle = NULL; + guint64 storage_available_size = 0L; //bytes + guint64 file_buffer_size = 0L; //bytes + gchar file_buffer_name[MM_MAX_URL_LEN] = {0}; + struct statfs buf = {0}; + gchar* factory_name = NULL; + + MMPLAYER_FENTER(); + return_if_fail(streamer); + return_if_fail(streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer); + + buffer_handle = &(streamer->buffer_handle[BUFFER_TYPE_MUXED]); + + if (!(buffer_handle && buffer_handle->buffer)) + { + debug_error("buffer_handle->buffer is NULL!"); + return; + } + + factory_name = GST_OBJECT_NAME(gst_element_get_factory(buffer_handle->buffer)); + + if (!factory_name) + { + debug_error("Fail to get factory name!"); + return; + } + + debug_log("target buffer elem : %s", GST_ELEMENT_NAME(buffer_handle->buffer)); + + if (!g_strrstr(factory_name, "queue2")) + { + debug_log("only queue2 can use file buffer. not decodebin2 or multiQ\n"); + return; + } + + if ((!use_file) || (!g_strrstr(factory_name, "queue2"))) + { + debug_log("use memory for buffering. streaming is played on push-based. \n" + "buffering position would not be updated.\n" + "buffered data would be flushed after played.\n" + "seeking and getting duration could be failed due to file format."); + return; + } + + debug_log("[Queue2] use file for buffering. streaming is played on pull-based. \n"); + + if (!file_path || strlen(file_path) <= 0) + file_path = g_strdup(DEFAULT_FILE_BUFFER_PATH); + + g_snprintf(file_buffer_name, MM_MAX_URL_LEN, "%s/XXXXXX", file_path); + secure_debug_log("[Queue2] the buffering file name is %s.\n", file_buffer_name); + + if (statfs((const char *)file_path, &buf) < 0) + { + debug_warning ("[Queue2] fail to get availabe storage capacity. just use file buffer.\n"); + file_buffer_size = 0L; + } + else + { + storage_available_size = (guint64)buf.f_bavail * (guint64)buf.f_bsize; //bytes + + debug_log ("[Queue2] the number of available blocks : %"G_GUINT64_FORMAT + ", the block size is %"G_GUINT64_FORMAT".\n", + (guint64)buf.f_bavail, (guint64)buf.f_bsize); + + debug_log ("[Queue2] calculated availabe storage size is %" + G_GUINT64_FORMAT" Bytes.\n", storage_available_size); + + if (content_size <= 0 || content_size >= storage_available_size) + file_buffer_size = storage_available_size; + else + file_buffer_size = 0L; + } + + if (file_buffer_size>0) + debug_log("[Queue2] use file ring buffer for buffering."); + + g_object_set (G_OBJECT(buffer_handle->buffer), "temp-template", file_buffer_name, NULL); + g_object_set (G_OBJECT(buffer_handle->buffer), "ring-buffer-max-size", file_buffer_size, NULL); + + MMPLAYER_FLEAVE(); + return; +} + +static void +streaming_set_buffer_size(mm_player_streaming_t* streamer, BufferType type, guint buffering_bytes, gdouble buffering_time) +{ + streaming_buffer_t* buffer_handle = NULL; + + MMPLAYER_FENTER(); + + return_if_fail(streamer); + return_if_fail(buffering_bytes > 0); + return_if_fail(type < BUFFER_TYPE_MAX); + + buffer_handle = &(streamer->buffer_handle[type]); + + if (buffer_handle && buffer_handle->buffer) + { + if (g_strrstr(GST_ELEMENT_NAME(buffer_handle->buffer), "multiqueue")) + { + if (buffering_time <= 0) + buffering_time = GET_CURRENT_BUFFERING_TIME(buffer_handle); + + g_object_set (G_OBJECT(buffer_handle->buffer), + "max-size-bytes", GET_MAX_BUFFER_BYTES(streamer), /* mq size is fixed, control it with high/low percent value*/ + "max-size-time", ((guint)ceil(buffering_time) * GST_SECOND), + "max-size-buffers", 0, NULL); /* disable */ + + buffer_handle->buffering_time = buffering_time; + buffer_handle->buffering_bytes = GET_MAX_BUFFER_BYTES(streamer); + + debug_log("max-size-time : %f", buffering_time); + } + else /* queue2 */ + { + if (buffer_handle->is_live) + { + g_object_set (G_OBJECT(buffer_handle->buffer), + "max-size-bytes", buffering_bytes, + "max-size-time", (guint64)(buffering_time*GST_SECOND), + "max-size-buffers", 0, + "use-rate-estimate", TRUE, NULL); + } + else + { + g_object_set (G_OBJECT(buffer_handle->buffer), + "max-size-bytes", buffering_bytes, + "max-size-time", (guint64)0, + "max-size-buffers", 0, + "use-rate-estimate", FALSE, NULL); + } + + buffer_handle->buffering_bytes = buffering_bytes; + buffer_handle->buffering_time = buffering_time; + + debug_log("max-size-bytes : %d", buffering_bytes); + } + } + + MMPLAYER_FLEAVE(); + return; +} + +void __mm_player_streaming_set_queue2( mm_player_streaming_t* streamer, + GstElement* buffer, + gboolean use_buffering, + guint buffering_bytes, + gdouble buffering_time, + gdouble low_percent, + gdouble high_percent, + gboolean use_file, + gchar* file_path, + guint64 content_size) +{ + MMPLAYER_FENTER(); + return_if_fail(streamer); + + if (buffer) + { + debug_log("USE-BUFFERING : %s", (use_buffering)?"OOO":"XXX"); + + streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer = buffer; + + if (use_buffering) + { + streamer->streaming_buffer_type = BUFFER_TYPE_MUXED; + + if (content_size > 0) + { + if (streamer->buffering_req.initial_second > 0) + streamer->buffering_req.is_pre_buffering = TRUE; + else + streamer->buffering_req.initial_second = (gint)ceil(buffering_time); + } + else + { + debug_log("live streaming without mq"); + + streamer->buffer_handle[BUFFER_TYPE_MUXED].is_live = TRUE; + streamer->buffering_req.initial_second = buffering_time = DEFAULT_BUFFERING_TIME; + } + } + + g_object_set ( G_OBJECT (streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), "use-buffering", use_buffering, NULL ); + } + + streaming_set_buffer_size (streamer, BUFFER_TYPE_MUXED, buffering_bytes, buffering_time); + streaming_set_buffer_percent (streamer, BUFFER_TYPE_MUXED, low_percent, high_percent, 0); + streaming_set_queue2_queue_type (streamer, use_file, file_path, content_size); + + MMPLAYER_FLEAVE(); + return; +} + +void __mm_player_streaming_sync_property(mm_player_streaming_t* streamer, GstElement* decodebin) +{ + streaming_buffer_t* buffer_handle = NULL; + + MMPLAYER_FENTER(); + + return_if_fail ( streamer && decodebin ); + + buffer_handle = &(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]); + + if ((streamer->need_sync) && (streamer->streaming_buffer_type == BUFFER_TYPE_DEMUXED)) + { + g_object_set (G_OBJECT(decodebin), + "max-size-bytes", buffer_handle->buffering_bytes, + "max-size-time", (guint64)(ceil(buffer_handle->buffering_time) * GST_SECOND), + "low-percent", (gint)buffer_handle->buffer_low_percent, + "high-percent", (gint)buffer_handle->buffer_high_percent, NULL); + + } + + streamer->need_sync = FALSE; +} + +void __mm_player_streaming_set_multiqueue( mm_player_streaming_t* streamer, + GstElement* buffer, + gboolean use_buffering, + gdouble buffering_time, + gdouble low_percent, + gdouble high_percent) +{ + streaming_buffer_t* buffer_handle = NULL; + gdouble pre_buffering_time = 0.0; + + MMPLAYER_FENTER(); + return_if_fail(streamer); + + buffer_handle = &(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]); + pre_buffering_time = (gdouble)streamer->buffering_req.initial_second; + + if (buffer) + { + buffer_handle->buffer = buffer; + + if (use_buffering) + { + streamer->streaming_buffer_type = BUFFER_TYPE_DEMUXED; + + // during prebuffering by requirement, buffer setting should not be changed. + if (pre_buffering_time > 0) + streamer->buffering_req.is_pre_buffering = TRUE; + } + + g_object_set ( G_OBJECT (buffer_handle->buffer), "use-buffering", use_buffering, NULL ); + } + + debug_log ("pre_buffering: %2.2f, during playing: %2.2f\n", pre_buffering_time, buffering_time); + + if (pre_buffering_time <= 0.0) + { + pre_buffering_time = GET_DEFAULT_PLAYING_TIME(streamer); + streamer->buffering_req.initial_second = (gint)ceil(buffering_time); + } + + high_percent = (pre_buffering_time * 100) / GET_MAX_BUFFER_TIME(streamer); + debug_log ("high_percent %2.3f %%\n", high_percent); + + streaming_set_buffer_size (streamer, BUFFER_TYPE_DEMUXED, GET_MAX_BUFFER_BYTES(streamer), GET_MAX_BUFFER_TIME(streamer)); + streaming_set_buffer_percent (streamer, BUFFER_TYPE_DEMUXED, low_percent, 0, high_percent); + + streamer->need_sync = TRUE; + + MMPLAYER_FLEAVE(); + return; +} + +static void +streaming_get_current_bitrate_info( mm_player_streaming_t* streamer, + GstMessage *buffering_msg, + streaming_content_info_t content_info, + streaming_bitrate_info_t* bitrate_info) +{ + + GstQuery *query = NULL; + GstBufferingMode mode = GST_BUFFERING_STREAM; + gint in_rate = 0; + gint out_rate = 0; + gint64 buffering_left = -1; + + guint buffer_criteria = 0; + guint estimated_content_bitrate = 0; + + gdouble buffer_buffering_time = DEFAULT_BUFFERING_TIME; + + MMPLAYER_FENTER(); + + return_if_fail(streamer); + return_if_fail(bitrate_info); + + if ((buffering_msg == NULL) || + ((streamer->buffer_handle[BUFFER_TYPE_DEMUXED].buffer != NULL) && + (streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer != NULL) && + (buffering_msg->src == (GstObject *)streamer->buffer_handle[BUFFER_TYPE_DEMUXED].buffer))) + { + query = gst_query_new_buffering (GST_FORMAT_PERCENT); + + if (gst_element_query ((streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), query)) + { + gst_query_parse_buffering_stats (query, &mode, &in_rate, &out_rate, &buffering_left); + } + + gst_query_unref (query); + } + else + { + gst_message_parse_buffering_stats (buffering_msg, &mode, &in_rate, &out_rate, &buffering_left); + } + + debug_log ("Streaming Info : in %d, out %d, left %lld\n", in_rate, out_rate, buffering_left); + + if ((content_info.content_size > 0) && (content_info.duration > 0) && ((content_info.duration/GST_SECOND) > 0)) + estimated_content_bitrate = GET_BIT_FROM_BYTE((guint)(content_info.content_size / (content_info.duration/GST_SECOND))); + + if (streamer->buffer_max_bitrate > 0) + { + streamer->buffer_max_bitrate = MAX(streamer->buffer_max_bitrate, streamer->buffer_avg_bitrate); + streamer->buffer_max_bitrate = MAX(streamer->buffer_max_bitrate, estimated_content_bitrate); + + buffer_criteria = GET_BYTE_FROM_BIT(streamer->buffer_max_bitrate); + + if (streamer->buffer_avg_bitrate > estimated_content_bitrate) + out_rate = GET_BYTE_FROM_BIT(streamer->buffer_avg_bitrate); + else if (estimated_content_bitrate != 0) + out_rate = GET_BYTE_FROM_BIT(estimated_content_bitrate); + else + out_rate = GET_BYTE_FROM_BIT(streamer->buffer_max_bitrate/3); + + debug_log ("(max)content_max_byte_rate %d, byte_out_rate %d\n", buffer_criteria, out_rate); + } + else if (streamer->buffer_avg_bitrate > 0) + { + buffer_criteria = GET_BYTE_FROM_BIT(streamer->buffer_avg_bitrate * 3); + out_rate = GET_BYTE_FROM_BIT(MAX(streamer->buffer_avg_bitrate,estimated_content_bitrate)); + + debug_log ("(avg)content_max_byte_rate %d, byte_out_rate %d\n", buffer_criteria, out_rate); + } + else + { + debug_warning ("There is no content bitrate information\n"); + } + + if ((in_rate > 0) && (out_rate > 0)) + buffer_buffering_time = (gdouble)out_rate / (gdouble)in_rate; + else if ((in_rate <= 0) && (out_rate > 0)) + buffer_buffering_time = MAX_BUFFERING_TIME; + else + buffer_buffering_time = DEFAULT_BUFFERING_TIME; + + (*bitrate_info).byte_in_rate = in_rate; + (*bitrate_info).byte_out_rate = out_rate; + (*bitrate_info).time_rate = buffer_buffering_time; + (*bitrate_info).buffer_criteria = buffer_criteria; +} + +static void +streaming_handle_fixed_buffering_mode( mm_player_streaming_t* streamer, + gint byte_out_rate, + gdouble fixed_buffering_time, + streaming_buffer_info_t* buffer_info) +{ + streaming_buffer_t* buffer_handle = NULL; + + guint buffering_bytes = 0; + gdouble buffering_time = 0.0; + gdouble per_byte = 0.0; + gdouble per_time = 0.0; + + return_if_fail(streamer); + return_if_fail(buffer_info); + + buffer_handle = &(streamer->buffer_handle[streamer->streaming_buffer_type]); + buffering_time = fixed_buffering_time; + + debug_log ("buffering time: %2.2f sec, out rate: %d\n", buffering_time, byte_out_rate); + + if ((buffering_time > 0) && (byte_out_rate > 0)) + { + buffering_bytes = GET_NEW_BUFFERING_BYTE(byte_out_rate * buffering_time); + } + else + { + if (buffering_time <= 0) + buffering_time = GET_CURRENT_BUFFERING_TIME(buffer_handle); + + debug_warning ("content bitrate is not updated yet.\n"); + buffering_bytes = GET_CURRENT_BUFFERING_BYTE(buffer_handle); + } + + GET_PERCENT(buffering_time, GET_CURRENT_BUFFERING_TIME(buffer_handle), buffer_handle->buffer_high_percent, per_time); + GET_PERCENT(buffering_bytes, GET_CURRENT_BUFFERING_BYTE(buffer_handle), buffer_handle->buffer_high_percent, per_byte); + + debug_log ("bytes %d, time %f, per_byte %f, per_time %f\n", + buffering_bytes, buffering_time, per_byte, per_time); + + (*buffer_info).buffering_bytes = buffering_bytes; + (*buffer_info).buffering_time = buffering_time; + (*buffer_info).percent_byte = per_byte; + (*buffer_info).percent_time = per_time; +} + +static void +streaming_handle_adaptive_buffering_mode( mm_player_streaming_t* streamer, + streaming_content_info_t content_info, + streaming_bitrate_info_t bitrate_info, + streaming_buffer_info_t* buffer_info, + gint expected_play_time) +{ + streaming_buffer_t* buffer_handle = NULL; + + gint buffering_bytes = 0; + gint adj_buffering_bytes = 0; + gdouble buffer_buffering_time = 0.0; + gdouble per_byte = 0.0; + gdouble per_time = 0.0; + gdouble portion = 0.0; + gdouble default_buffering_time = 0.0; + + return_if_fail(streamer); + return_if_fail(buffer_info); + + debug_log ("pos %lld, dur %lld, size %lld, in/out:%d/%d, buffer_criteria:%d, time_rate:%f, need:%d sec\n", + content_info.position, content_info.duration, content_info.content_size, + bitrate_info.byte_in_rate, bitrate_info.byte_out_rate, + bitrate_info.buffer_criteria, bitrate_info.time_rate, expected_play_time); + + if (((expected_play_time == TO_THE_END) && (content_info.position <= 0)) || + (content_info.duration <= 0) || + (content_info.content_size <= 0)) + { + debug_warning ("keep previous setting.\n"); + return; + } + + if ((bitrate_info.byte_out_rate <= 0) || (bitrate_info.buffer_criteria == 0)) + { + debug_warning ("keep previous setting.\n"); + return; + } + + buffer_handle = &(streamer->buffer_handle[streamer->streaming_buffer_type]); + + if (bitrate_info.byte_in_rate < bitrate_info.byte_out_rate) + { + if (expected_play_time != TO_THE_END) + portion = (double)(expected_play_time * GST_SECOND) / (double)content_info.duration; + else + portion = (1 - (double)content_info.position/(double)content_info.duration); + + buffering_bytes = GET_NEW_BUFFERING_BYTE(((double)content_info.content_size * portion) \ + * (1 - (double)bitrate_info.byte_in_rate/(double)bitrate_info.byte_out_rate)); + } + else + { + /* buffering_bytes will be set as streamer->default_val.buffering_time * + * receiving rate is bigger than avg content bitrate + * so there is no reason to buffering. if the buffering msg is posted + * in-rate or contents bitrate has wrong value. */ + debug_warning ("don't need to do buffering.\n"); + } + + if (buffering_bytes > 0) + buffer_buffering_time = (gdouble)buffering_bytes / (gdouble)bitrate_info.byte_out_rate; + + if (content_info.position <= 0) + { + /* if the buffer is filled under 50%, MSL use the original default buffering time. + if not, MSL use just 2 sec as a default buffering time. (to reduce initial buffering time) */ + default_buffering_time = streamer->default_val.buffering_time - (streamer->buffering_percent/50); + } + else + { + default_buffering_time = streamer->default_val.buffering_time; + } + + if (buffer_buffering_time < default_buffering_time) + { + debug_log ("adjusted time: %2.2f -> %2.2f\n", buffer_buffering_time, default_buffering_time); + debug_log ("adjusted bytes : %d or %d or %d\n", + buffering_bytes, + (gint)(bitrate_info.byte_out_rate * buffer_buffering_time), + (gint)(bitrate_info.buffer_criteria * buffer_buffering_time)); + + if (content_info.position > 0) + { + /* start monitoring the abmormal state */ + streamer->default_val.buffering_monitor = TRUE; + } + + buffer_buffering_time = default_buffering_time; + adj_buffering_bytes = GET_NEW_BUFFERING_BYTE(bitrate_info.byte_out_rate * (gint)ceil(buffer_buffering_time)); + buffering_bytes = MAX(buffering_bytes, adj_buffering_bytes); + } + + GET_PERCENT(buffering_bytes, GET_CURRENT_BUFFERING_BYTE(buffer_handle), buffer_handle->buffer_high_percent, per_byte); + GET_PERCENT(buffer_buffering_time, GET_CURRENT_BUFFERING_TIME(buffer_handle), buffer_handle->buffer_high_percent, per_time); + + debug_log ("monitor %d, bytes %d, time %f, per_byte %f, per_time %f\n", + streamer->default_val.buffering_monitor, + buffering_bytes, buffer_buffering_time, per_byte, per_time); + + (*buffer_info).buffering_bytes = buffering_bytes; + (*buffer_info).buffering_time = buffer_buffering_time; + (*buffer_info).percent_byte = per_byte; + (*buffer_info).percent_time = per_time; + +} + +static void +streaming_update_buffer_setting ( mm_player_streaming_t* streamer, + GstMessage *buffering_msg, // can be null + guint64 content_size, + gint64 position, + gint64 duration) +{ + streaming_buffer_t* buffer_handle = NULL; + MMPlayerBufferingMode buffering_mode = MM_PLAYER_BUFFERING_MODE_ADAPTIVE; + + streaming_buffer_info_t buffer_info; + streaming_content_info_t content_info; + streaming_bitrate_info_t bitrate_info; + + gdouble low_percent = 0.0; + + MMPLAYER_FENTER(); + + return_if_fail ( streamer ); + + memset(&buffer_info, 0x00, sizeof(streaming_buffer_info_t)); + memset(&content_info, 0x00, sizeof(streaming_content_info_t)); + memset(&bitrate_info, 0x00, sizeof(streaming_bitrate_info_t)); + + buffer_handle = &(streamer->buffer_handle[streamer->streaming_buffer_type]); + + if (streamer->buffering_req.is_pre_buffering == TRUE) + buffering_mode = MM_PLAYER_BUFFERING_MODE_FIXED; + else + buffering_mode = streamer->buffering_req.mode; + + buffer_info.buffering_bytes = buffer_handle->buffering_bytes; + buffer_info.buffering_time = buffer_handle->buffering_time; + buffer_info.percent_byte = buffer_handle->buffer_high_percent; + buffer_info.percent_time = buffer_handle->buffer_high_percent; + + content_info.position = position; + content_info.duration = duration; + content_info.content_size = content_size; + + streaming_get_current_bitrate_info(streamer, buffering_msg, content_info, &bitrate_info); + + debug_log ("buffering mode %d, new info in_r:%d, out_r:%d, cb:%d, bt:%f\n", + buffering_mode, bitrate_info.byte_in_rate, bitrate_info.byte_out_rate, + bitrate_info.buffer_criteria, bitrate_info.time_rate); + + /* calculate buffer low/high percent */ + low_percent = DEFAULT_BUFFER_LOW_PERCENT; + + /******************** + * (1) fixed mode * + ********************/ + + if (buffering_mode == MM_PLAYER_BUFFERING_MODE_FIXED) + { + gdouble buffering_time = 0.0; + + if (streamer->buffering_req.is_pre_buffering == TRUE) + buffering_time = (gdouble)streamer->buffering_req.initial_second; + else + buffering_time = (gdouble)streamer->buffering_req.runtime_second; + + streaming_handle_fixed_buffering_mode(streamer, bitrate_info.byte_out_rate, buffering_time, &buffer_info); + } + + /*********************************** + * (2) once mode for samsung link * + ***********************************/ + else if (buffering_mode == MM_PLAYER_BUFFERING_MODE_SLINK) + { + streaming_handle_adaptive_buffering_mode(streamer, content_info, bitrate_info, &buffer_info, TO_THE_END); + } + + /********************************* + * (3) adaptive mode (default) * + *********************************/ + else + { + gint expected_play_time = DEFAULT_PLAYING_TIME; + + if (streamer->buffering_req.runtime_second > 0) + { + expected_play_time = streamer->buffering_req.runtime_second; + } + else if ((position == 0) && (streamer->is_buffering)) + { + expected_play_time = streamer->buffering_req.initial_second; + } + + if (expected_play_time <= 0) + expected_play_time = DEFAULT_PLAYING_TIME; + + streaming_handle_adaptive_buffering_mode(streamer, content_info, bitrate_info, &buffer_info, expected_play_time); + + if (IS_MUXED_BUFFERING_MODE(streamer)) // even if new byte size is smaller than the previous one, time need to be updated. + buffer_handle->buffering_time = buffer_info.buffering_time; + } + + debug_log ("adj buffer(%d) %d->%d bytes/%2.2f->%2.2f sec\n", + streamer->streaming_buffer_type, + GET_CURRENT_BUFFERING_BYTE(buffer_handle), buffer_info.buffering_bytes, + GET_CURRENT_BUFFERING_TIME(buffer_handle), buffer_info.buffering_time); + + /* queue2 : bytes, multiqueue : time */ + if (((GET_CURRENT_BUFFERING_BYTE(buffer_handle) < buffer_info.buffering_bytes) && IS_MUXED_BUFFERING_MODE(streamer)) || + ((GET_CURRENT_BUFFERING_TIME(buffer_handle) < buffer_info.buffering_time) && IS_DEMUXED_BUFFERING_MODE(streamer))) + { + if (duration > 0 && position > 0) + { + gdouble buffering_time_limit = (gdouble)(duration - position)/GST_SECOND; + + if (buffer_info.buffering_time > buffering_time_limit) + buffer_info.buffering_time = buffering_time_limit; + } + + streaming_set_buffer_size(streamer, streamer->streaming_buffer_type, buffer_info.buffering_bytes, buffer_info.buffering_time); + } + + streaming_set_buffer_percent(streamer, streamer->streaming_buffer_type, low_percent, buffer_info.percent_byte, buffer_info.percent_time); + + debug_log("buffer setting: size %d, time %f, per %f\n", + GET_CURRENT_BUFFERING_BYTE(buffer_handle), + GET_CURRENT_BUFFERING_TIME(buffer_handle), + buffer_handle->buffer_high_percent); + + streamer->need_sync = TRUE; +} + +static void +streaming_adjust_min_threshold(mm_player_streaming_t* streamer, gint64 position) +{ +#define DEFAULT_TIME_PAD 1 /* sec */ + gint playing_time = 0; + + MMPLAYER_FENTER(); + + return_if_fail(streamer); + + playing_time = (gint)((position - streamer->default_val.prev_pos) / GST_SECOND); + + debug_log ("buffering monitor = %s\n", (streamer->default_val.buffering_monitor)?"ON":"OFF"); + debug_log ("playing_time ( %d sec) = %lld - %lld \n", playing_time, position, streamer->default_val.prev_pos); + debug_log ("default time : %2.3f, prev buffering t : %2.3f\n", + streamer->default_val.buffering_time, streamer->buffer_handle[streamer->streaming_buffer_type].buffering_time); + + if ((streamer->default_val.buffering_monitor) && (playing_time <= (gint)streamer->default_val.buffering_time)) + { + gint time_gap = 0; + time_gap = (gint)(streamer->default_val.buffering_time - DEFAULT_BUFFERING_TIME); + if (time_gap <= 0) + time_gap = DEFAULT_TIME_PAD; + + streamer->default_val.buffering_time += time_gap*2; + streamer->default_val.buffering_time = MIN(streamer->default_val.buffering_time, MAX_BUFFERING_TIME); + } + else + { + streamer->default_val.buffering_time = DEFAULT_BUFFERING_TIME; + } + + debug_log ("new default min value %2.3f \n", streamer->default_val.buffering_time); + + streamer->default_val.buffering_monitor = FALSE; + streamer->default_val.prev_pos = position; +} + +static void +streaming_update_buffering_status(mm_player_streaming_t* streamer, GstMessage *buffering_msg, gint64 position) +{ + gint buffer_percent = 0; + gboolean increased_per = TRUE; + + MMPLAYER_FENTER(); + + return_if_fail(streamer); + return_if_fail(buffering_msg); + + /* update when buffering has started. */ + if ( !streamer->is_buffering ) + { + streamer->is_buffering = TRUE; + streamer->is_buffering_done = FALSE; + streamer->buffering_percent = -1; + + if (!streamer->buffering_req.is_pre_buffering) + { + streamer->need_update = TRUE; + streaming_adjust_min_threshold(streamer, position); + } + } + + /* update buffer percent */ + gst_message_parse_buffering (buffering_msg, &buffer_percent); + + if (streamer->buffering_percent < buffer_percent) + { + debug_log ("[%s] buffering %d%%....\n", + GST_OBJECT_NAME(GST_MESSAGE_SRC(buffering_msg)), buffer_percent); + streamer->buffering_percent = buffer_percent; + } + else + { + increased_per = FALSE; + } + + if ((streamer->buffering_percent == MAX_BUFFER_PERCENT) || (streamer->is_buffering_done == TRUE)) + { + streamer->is_buffering = FALSE; + streamer->buffering_req.is_pre_buffering = FALSE; + if (streamer->buffering_percent == MAX_BUFFER_PERCENT) + streamer->is_buffering_done = FALSE; + else + streamer->buffering_percent = MAX_BUFFER_PERCENT; + } + else + { + /* need to update periodically in case of slink mode */ + if ((increased_per == TRUE) && + (buffer_percent%10 == 0) && + (streamer->buffering_req.mode == MM_PLAYER_BUFFERING_MODE_SLINK) && + (streamer->buffering_req.is_pre_buffering == FALSE)) + { + /* Update buffer setting to reflect data receiving rate for slink mode */ + streamer->need_update = TRUE; + } + } +} + +void __mm_player_streaming_buffering( mm_player_streaming_t* streamer, + GstMessage *buffering_msg, + guint64 content_size, + gint64 position, + gint64 duration) +{ + MMPLAYER_FENTER(); + + return_if_fail ( streamer ); + return_if_fail ( buffering_msg ); + return_if_fail ( GST_IS_MESSAGE ( buffering_msg ) ); + return_if_fail ( (GST_MESSAGE_TYPE ( buffering_msg ) == GST_MESSAGE_BUFFERING) ); + + if (buffering_msg) + { + if (position > (gint64)(streamer->buffering_req.initial_second * GST_SECOND)) + streamer->buffering_req.is_pre_buffering = FALSE; + + streaming_update_buffering_status(streamer, buffering_msg, position); + + if (!streamer->need_update) + { + //debug_log ("don't need to update buffering stats during buffering.\n"); + return; + } + + streamer->need_update = FALSE; + } + + streaming_update_buffer_setting (streamer, buffering_msg, content_size, position, duration); + + return; +} + diff --git a/src/server/mm_player_tracks.c b/src/server/mm_player_tracks.c new file mode 100644 index 0000000..3b19e8c --- /dev/null +++ b/src/server/mm_player_tracks.c @@ -0,0 +1,509 @@ +/* + * libmm-player + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , naveen cherukuri , + * YeJin Cho , YoungHwan An + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include +#include +#include +#include "mm_player_utils.h" +#include "mm_player_tracks.h" + +/*--------------------------------------------------------------------------------------- +| LOCAL FUNCTION PROTOTYPES: | +---------------------------------------------------------------------------------------*/ +static int __mmplayer_track_get_language(mm_player_t* player, MMPlayerTrackType type, gint stream_index, gchar **code); + + +/*======================================================================================= +| FUNCTION DEFINITIONS | +=======================================================================================*/ +int _mmplayer_get_track_count(MMHandleType hplayer, MMPlayerTrackType type, int *count) +{ + mm_player_t* player = (mm_player_t*) hplayer; + MMHandleType attrs = 0; + int ret = MM_ERROR_NONE; + + MMPLAYER_FENTER(); + + /* check player handle */ + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + return_val_if_fail(count, MM_ERROR_COMMON_INVALID_ARGUMENT); + return_val_if_fail((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED) + ||(MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING), + MM_ERROR_PLAYER_INVALID_STATE); + + attrs = MMPLAYER_GET_ATTRS(player); + if ( !attrs ) + { + debug_error("cannot get content attribute"); + return MM_ERROR_PLAYER_INTERNAL; + } + + switch (type) + { + case MM_PLAYER_TRACK_TYPE_AUDIO: + { + /*if function called for normal file [no multi audio] */ + if(player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) + { + *count = 0; + break; + } + ret = mm_attrs_get_int_by_name(attrs, "content_audio_track_num", count); + } + break; + case MM_PLAYER_TRACK_TYPE_TEXT: + ret = mm_attrs_get_int_by_name(attrs, "content_text_track_num", count); + break; + default: + ret = MM_ERROR_COMMON_INVALID_ARGUMENT; + break; + } + + debug_log ("%d track num : %d\n", type, *count); + + MMPLAYER_FLEAVE(); + + return ret; +} + +int _mmplayer_select_track(MMHandleType hplayer, MMPlayerTrackType type, int index) +{ + int ret = MM_ERROR_NONE; + mm_player_t* player = (mm_player_t*) hplayer; + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_FENTER(); + + + if (type == MM_PLAYER_TRACK_TYPE_TEXT && player->subtitle_language_list) + { + GstElement *subparse = NULL; + MMPlayerLangStruct *temp = NULL; + unsigned long cur_time = 0; + + if(!player->pipeline || !player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst) + { + ret = MM_ERROR_PLAYER_NOT_INITIALIZED; + goto EXIT; + } + + _mmplayer_get_position (hplayer, MM_PLAYER_POS_FORMAT_TIME, &cur_time); + temp = g_list_nth_data (player->subtitle_language_list, index); + + subparse = player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst; + debug_log("setting to language %s", temp->language_code); + g_object_set (G_OBJECT (subparse), "current-language", temp->language_key, NULL); + + _mmplayer_sync_subtitle_pipeline(player); + + } + else + { + ret = _mmplayer_change_track_language (hplayer, type, index); + } + +EXIT: + MMPLAYER_FLEAVE(); + return ret; +} + +#ifdef _MULTI_TRACK +int _mmplayer_track_add_subtitle_language(MMHandleType hplayer, int index) +{ + int ret = MM_ERROR_NONE; + mm_player_t* player = (mm_player_t*) hplayer; + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_FENTER(); + + if(!player->pipeline || !player->pipeline->mainbin[MMPLAYER_M_T_SUBMUX_EXTERNAL].gst) + { + ret = MM_ERROR_PLAYER_NOT_INITIALIZED; + goto EXIT; + } + + if (player->subtitle_language_list) + { + GstElement *subparse = NULL; + MMPlayerLangStruct *temp = NULL; + + temp = g_list_nth_data (player->subtitle_language_list, index); + temp->active = TRUE; + + subparse = player->pipeline->mainbin[MMPLAYER_M_T_SUBMUX_EXTERNAL].gst; + debug_log("adding to language %s", temp->language_code); + g_object_set (G_OBJECT (subparse), "current-language", temp->language_key, NULL); + g_object_set (G_OBJECT (subparse), "lang-list", player->subtitle_language_list, NULL); + + _mmplayer_sync_subtitle_pipeline(player); + } + else + { + debug_warning("It is for just subtitle track"); + ret = MM_ERROR_PLAYER_NO_OP; + goto EXIT; + } + +EXIT: + MMPLAYER_FLEAVE(); + return ret; +} + +int _mmplayer_track_remove_subtitle_language(MMHandleType hplayer, int index) +{ + int ret = MM_ERROR_NONE; + mm_player_t* player = (mm_player_t*) hplayer; + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_FENTER(); + + if(!player->pipeline || !player->pipeline->mainbin[MMPLAYER_M_T_SUBMUX_EXTERNAL].gst) + { + ret = MM_ERROR_PLAYER_NOT_INITIALIZED; + goto EXIT; + } + + if (player->subtitle_language_list) + { + GstElement *subparse = NULL; + MMPlayerLangStruct *temp = NULL; + + temp = g_list_nth_data (player->subtitle_language_list, index); + temp->active = FALSE; + + subparse = player->pipeline->mainbin[MMPLAYER_M_T_SUBMUX_EXTERNAL].gst; + debug_log("removing to language %s", temp->language_code); + g_object_set (G_OBJECT (subparse), "current-language", temp->language_key, NULL); + g_object_set (G_OBJECT (subparse), "lang-list", player->subtitle_language_list, NULL); + + _mmplayer_sync_subtitle_pipeline(player); + } + else + { + debug_warning("It is for just subtitle track"); + ret = MM_ERROR_PLAYER_NO_OP; + goto EXIT; + } + +EXIT: + MMPLAYER_FLEAVE(); + return ret; +} +#endif +int _mmplayer_get_current_track(MMHandleType hplayer, MMPlayerTrackType type, int *index) +{ + int ret = MM_ERROR_NONE; + mm_player_t* player = (mm_player_t*) hplayer; + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_FENTER(); + + if (type >= MM_PLAYER_TRACK_TYPE_MAX) + { + ret = MM_ERROR_INVALID_ARGUMENT; + debug_log("Not a proper type [type:%d] \n", type); + goto EXIT; + } + + if (type == MM_PLAYER_TRACK_TYPE_TEXT && player->subtitle_language_list) + { + GstElement *subparse = NULL; + int total_track_count = 0; + gchar* current_language = NULL; + MMPlayerLangStruct *temp = NULL; + MMHandleType attrs = 0; + + attrs = MMPLAYER_GET_ATTRS(player); + if (!attrs) + { + debug_error("cannot get content attribute"); + ret = MM_ERROR_PLAYER_INTERNAL; + goto EXIT; + } + + mm_attrs_get_int_by_name(attrs, "content_text_track_num", &total_track_count); + + subparse = player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst; + g_object_get (G_OBJECT (subparse), "current-language", ¤t_language, NULL); + debug_log("current language is %s ",current_language); + while (total_track_count) + { + temp = g_list_nth_data (player->subtitle_language_list, total_track_count - 1); + if (temp) + { + debug_log("find the list"); + if (!strcmp(temp->language_key, current_language)) + { + *index = total_track_count - 1; + debug_log("current lang index is %d", *index); + break; + } + } + total_track_count--; + } + } + else + { + if (player->selector[type].total_track_num <= 0) + { + ret = MM_ERROR_PLAYER_NO_OP; + debug_log("there is no track information [type:%d] \n", type); + goto EXIT; + } + + *index = player->selector[type].active_pad_index; + } + +EXIT: + MMPLAYER_FLEAVE(); + return ret; +} + +int _mmplayer_get_track_language_code(MMHandleType hplayer, MMPlayerTrackType type, int index, char **code) +{ + int ret = MM_ERROR_NONE; + + return_val_if_fail(hplayer, MM_ERROR_PLAYER_NOT_INITIALIZED); + mm_player_t* player = (mm_player_t*) hplayer; + MMPLAYER_FENTER(); + + if (type == MM_PLAYER_TRACK_TYPE_TEXT && player->subtitle_language_list) + { + int language_code_size = 3;/*Size of ISO-639-1*/ + MMPlayerLangStruct *language_list = NULL; + + *code = (char*)malloc(language_code_size * sizeof(char)); + if (*code == NULL) + { + ret = MM_ERROR_PLAYER_INTERNAL; + goto EXIT; + } + memset(*code, 0, language_code_size * sizeof(char)); + + language_list = g_list_nth_data (player->subtitle_language_list, index); + if (language_list == NULL) + { + debug_log ("%d is not a proper index \n", index); + goto EXIT; + } + strncpy(*code, language_list->language_code, language_code_size); + } + else + { + if (player->selector[type].total_track_num <= 0) + { + ret = MM_ERROR_PLAYER_NO_OP; + debug_log("language list is not available. [type:%d] \n", type); + goto EXIT; + } + + if(index < 0 || index >= player->selector[type].total_track_num) + { + ret = MM_ERROR_INVALID_ARGUMENT; + debug_log("Not a proper index : %d \n", index); + goto EXIT; + } + + ret = __mmplayer_track_get_language(player, type, index, code); + } + +EXIT: + MMPLAYER_FLEAVE(); + return ret; +} + +void _mmplayer_track_initialize(mm_player_t* player) +{ + MMPlayerTrackType type = MM_PLAYER_TRACK_TYPE_AUDIO; + + MMPLAYER_FENTER(); + + for (;typeselector[type].total_track_num = 0; + player->selector[type].channels = g_ptr_array_new(); + } +} + +void _mmplayer_track_destroy(mm_player_t* player) +{ + MMPlayerTrackType type = MM_PLAYER_TRACK_TYPE_AUDIO; + MMHandleType attrs = 0; + MMPLAYER_FENTER(); + + attrs = MMPLAYER_GET_ATTRS(player); + if (attrs) + { + mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 0); + mm_attrs_set_int_by_name(attrs, "content_video_track_num", 0); + mm_attrs_set_int_by_name(attrs, "content_text_track_num", 0); + + if (mmf_attrs_commit (attrs)) + debug_error("failed to commit.\n"); + } + + for (;typeselector[type].active_pad_index = 0; + player->selector[type].total_track_num = 0; + + if (player->selector[type].channels) + g_ptr_array_free (player->selector[type].channels, TRUE); + player->selector[type].channels = NULL; + } +} + +void _mmplayer_track_update_info(mm_player_t* player, MMPlayerTrackType type, GstPad *sinkpad) +{ + MMPLAYER_FENTER(); + + player->selector[type].total_track_num++; + g_ptr_array_add (player->selector[type].channels, sinkpad); + + debug_log ("type:%d, total track:%d\n", type, player->selector[type].total_track_num); +} + +static int __mmplayer_track_get_language(mm_player_t* player, MMPlayerTrackType type, gint stream_index, gchar **code) +{ + int ret = MM_ERROR_NONE; + + GstTagList *tag_list = NULL; + gchar* tag = NULL; + GstPad *sinkpad = NULL; + gint language_code_size = 3; /*Size of ISO-639-1*/ + + MMPLAYER_FENTER(); + + *code = (char *)malloc(language_code_size*sizeof(char)); + if(*code == NULL) + { + ret = MM_ERROR_PLAYER_INTERNAL; + goto EXIT; + } + memset(*code,0,language_code_size*sizeof(char)); + + debug_log ("total track num : %d , req idx : %d\n", player->selector[type].total_track_num, stream_index); + + if (stream_index < player->selector[type].total_track_num) + { + sinkpad = g_ptr_array_index (player->selector[type].channels, stream_index); + } + else + { + ret = MM_ERROR_INVALID_ARGUMENT; + goto EXIT; + } + + g_object_get (sinkpad, "tags", &tag_list, NULL); + //secure_debug_log ("[%s]\n", gst_tag_list_to_string(tag_list)); + + gst_tag_list_get_string (tag_list, GST_TAG_LANGUAGE_CODE, &tag); + + if(!tag) + { + debug_log("there is no lang info - und\n"); + strncpy(*code, "und", language_code_size); + } + else + { + debug_log("language information[%d] code: %s, len: %d \n", type, tag, strlen(tag)); + strncpy(*code, tag, /*strlen(tag)*/language_code_size); + g_free (tag); + } + + if (tag_list) + gst_tag_list_free (tag_list); + +EXIT: + MMPLAYER_FLEAVE(); + return ret; +} +#ifdef _MULTI_TRACK +int _mmplayer_track_foreach_selected_subtitle_language(MMHandleType hplayer,_mmplayer_track_selected_subtitle_language_cb foreach_cb, void *user_data) +{ + int ret = MM_ERROR_NONE; + mm_player_t* player = (mm_player_t*) hplayer; + return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + MMPLAYER_FENTER(); + + int index = -1; + + if (player->subtitle_language_list) + { + int total_track_count = 0; + MMPlayerLangStruct *temp = NULL; + MMHandleType attrs = 0; + + attrs = MMPLAYER_GET_ATTRS(player); + if (!attrs) + { + debug_error("cannot get content attribute"); + ret = MM_ERROR_PLAYER_INTERNAL; + goto EXIT; + } + mm_attrs_get_int_by_name(attrs, "content_text_track_num", &total_track_count); + + if(!total_track_count) + { + debug_warning("There are no subtitle track selected."); + ret = MM_ERROR_PLAYER_NO_OP; + goto EXIT; + } + + while (total_track_count) + { + temp = g_list_nth_data (player->subtitle_language_list, total_track_count - 1); + if (temp) + { + debug_log("find the list"); + if (temp->active) + { + index = total_track_count - 1; + debug_log("active subtitle track index is %d", index); + if (!foreach_cb(index, user_data)) + { + ret = MM_ERROR_PLAYER_INTERNAL; + goto CALLBACK_ERROR; + } + } + } + total_track_count--; + } + + debug_log("we will return -1 for notifying the end to user"); + + /* After returning all selected indexs, we will return -1 for notifying the end to user */ + if (!foreach_cb(-1, user_data)) + { + ret = MM_ERROR_PLAYER_INTERNAL; + goto CALLBACK_ERROR; + } + } + +CALLBACK_ERROR: + debug_error("foreach callback returned error"); + +EXIT: + MMPLAYER_FLEAVE(); + return ret; + + +} +#endif diff --git a/src/server/mm_player_utils.c b/src/server/mm_player_utils.c new file mode 100644 index 0000000..937c91f --- /dev/null +++ b/src/server/mm_player_utils.c @@ -0,0 +1,518 @@ +/* + * libmm-player + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , YeJin Cho , + * Seungbae Shin , YoungHwan An + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "mm_player_utils.h" + +/* for getting status of connecting external display */ +#include +#include +#include + +int util_exist_file_path(const char *file_path) +{ + int fd = 0; + struct stat stat_results = {0, }; + + if (!file_path || !strlen(file_path)) + return MM_ERROR_PLAYER_FILE_NOT_FOUND; + + fd = open (file_path, O_RDONLY); + + if (fd < 0) + { + debug_error("failed to open file by %s (%d)", strerror(errno), errno); + + if (EACCES == errno) + return MM_ERROR_PLAYER_PERMISSION_DENIED; + + return MM_ERROR_PLAYER_FILE_NOT_FOUND; + } + + if (fstat(fd, &stat_results) < 0) + { + debug_error("failed to get file status"); + } + else if (stat_results.st_size == 0) + { + debug_error("file size is zero"); + close(fd); + return MM_ERROR_PLAYER_FILE_NOT_FOUND; + } + else + { + debug_warning("file size : %lld bytes", (long long)stat_results.st_size); + } + + close(fd); + + return MM_ERROR_NONE; +} + +bool util_write_file_backup(const char *backup_path, char *data_ptr, int data_size) +{ + FILE *fp = NULL; + int wsize = 0; + + fp = fopen(backup_path, "wb"); + if (!fp) + return FALSE; + + wsize = fwrite(data_ptr, sizeof(char), data_size, fp); + + fclose(fp); + + if (wsize != data_size) { + if (!access(backup_path, R_OK)) + remove(backup_path); + + debug_error("No space to write!\n"); + + return FALSE; + } + + return TRUE; +} + +bool util_remove_file_backup(const char *backup_path) +{ + if (!backup_path || !strlen(backup_path)) + return FALSE; + + int res = access(backup_path, R_OK); + if (!res) + { + if (remove(backup_path) == -1) + return FALSE; + } + + return TRUE; +} + +#define DETECTION_PREFIX_SIZE 20 +//bool util_is_midi_type_by_mem(void *mem, int size) +int util_is_midi_type_by_mem(void *mem, int size) +{ + const char *p = (const char *)mem; + + if (size < DETECTION_PREFIX_SIZE) + return MM_AUDIO_CODEC_INVALID; + + /* mmf file detection */ + if (p[0] == 'M' && p[1] == 'M' && p[2] == 'M' && p[3] == 'D') { + debug_log("MM_AUDIO_CODEC_MMF\n"); + return MM_AUDIO_CODEC_MMF; + } + + /* midi file detection */ + if (p[0] == 'M' && p[1] == 'T' && p[2] == 'h' && p[3] == 'd') { + debug_log ("MM_AUDIO_CODEC_MIDI, %d\n", MM_AUDIO_CODEC_MIDI); + return MM_AUDIO_CODEC_MIDI; + } + /* mxmf file detection */ + if (p[0] == 'X' && p[1] == 'M' && p[2] == 'F' && p[3] == '_') { + debug_log ("MM_AUDIO_CODEC_MXMF\n"); + return MM_AUDIO_CODEC_MXMF; + } + + /* wave file detection */ + if (p[0] == 'R' && p[1] == 'I' && p[2] == 'F' && p[3] == 'F' && + p[8] == 'W' && p[9] == 'A' && p[10] == 'V' && p[11] == 'E' && + p[12] == 'f' && p[13] == 'm' && p[14] == 't') { + debug_log ("MM_AUDIO_CODEC_WAVE\n"); + return MM_AUDIO_CODEC_WAVE; + } + /* i-melody file detection */ + if (memcmp(p, "BEGIN:IMELODY", 13) == 0) + { + debug_log ("MM_AUDIO_CODEC_IMELODY\n"); + return MM_AUDIO_CODEC_IMELODY; + } + + return MM_AUDIO_CODEC_INVALID; +} + +//bool util_is_midi_type_by_file(const char *file_path) +int util_is_midi_type_by_file(const char *file_path) +{ + struct stat file_attrib; + FILE *fp = NULL; + char prefix[DETECTION_PREFIX_SIZE] = {0,}; + int size; + + if (!file_path) + return FALSE; + + fp = fopen(file_path, "r"); + + if (!fp) + return FALSE; + + memset(&file_attrib, 0, sizeof(file_attrib)); + + if (stat(file_path, &file_attrib) != 0) + { + fclose(fp); + return FALSE; + } + + size = (int) file_attrib.st_size; + + if (size < DETECTION_PREFIX_SIZE) + { + fclose(fp); + return FALSE; + } + + size = fread(prefix, sizeof(char), DETECTION_PREFIX_SIZE, fp); + + fclose(fp); + + return util_is_midi_type_by_mem(prefix, size); +} + +char** +util_get_cookie_list ( const char *cookies ) +{ + char **cookie_list = NULL; + char *temp = NULL; + gint i = 0; + + if ( !cookies || !strlen(cookies) ) + return NULL; + + secure_debug_log("cookies : %d[bytes] - %s \n", strlen(cookies), cookies); + + temp = g_strdup(cookies); + + /* trimming. it works inplace */ + g_strstrip(temp); + + /* split */ + cookie_list = g_strsplit(temp, ";", 100); + + for ( i = 0; i < g_strv_length(cookie_list); i++ ) + { + if ( cookie_list[i] && strlen(cookie_list[i]) ) + { + g_strstrip(cookie_list[i]); + secure_debug_log("cookie_list[%d] : %d[bytes] - %s \n", i, strlen(cookie_list[i]), cookie_list[i]); + } + else + { + cookie_list[i][0]='\0'; + } + } + + if (temp) + g_free (temp); + temp=NULL; + + return cookie_list; +} + +bool util_check_valid_url ( const char *proxy ) +{ + struct in_addr proxy_addr; + bool ret = TRUE; + + return_val_if_fail ( proxy, FALSE ); + return_val_if_fail ( strlen(proxy), FALSE ); + + if ( inet_aton(proxy, &proxy_addr) != 0 ) + { + debug_warning("invalid proxy is set. \n"); + ret = FALSE; + } + + return ret; +} + +/* check the given path is indicating sdp file */ +bool +util_is_sdp_file ( const char *path ) +{ + gboolean ret = FALSE; + gchar* uri = NULL; + + MMPLAYER_FENTER(); + + return_val_if_fail ( path, FALSE ); + + uri = g_ascii_strdown ( path, -1 ); + + if ( uri == NULL) + { + return FALSE; + } + + /* trimming */ + g_strstrip( uri ); + + /* strlen(".sdp") == 4 */ + if ( strlen( uri ) <= 4 ) + { + debug_warning ( "path is too short.\n" ); + return ret; + } + + /* first, check extension name */ + ret = g_str_has_suffix ( uri, "sdp" ); + + /* second, if no suffix is there, check it's contents */ + if ( ! ret ) + { + /* FIXIT : do it soon */ + } + + g_free( uri); + uri = NULL; + + return ret; +} + +int64_t +util_get_time ( void ) +{ + struct timeval tv; + gettimeofday(&tv,NULL); + return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec; +} + +int +util_get_rank_increase ( const char *factory_class ) +{ + gint rank_pri_inc = 20; + gint rank_sec_inc = 10; + gint ret = 0; + + if ( g_strrstr(factory_class,"Dsp") ) + ret = rank_pri_inc; + else if ( g_strrstr(factory_class,"HW") ) + ret = rank_pri_inc; + else if ( g_strrstr(factory_class,"Arm") ) + ret = rank_sec_inc; + + return ret; +} + +int +util_factory_rank_compare(GstPluginFeature *f1, GstPluginFeature *f2) // @ +{ + const gchar *klass; + int f1_rank_inc=0, f2_rank_inc=0; + + klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(f1)); + f1_rank_inc = util_get_rank_increase ( klass ); + + klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(f2)); + f2_rank_inc = util_get_rank_increase ( klass ); + + return (gst_plugin_feature_get_rank(f2)+f2_rank_inc) - (gst_plugin_feature_get_rank(f1)+f1_rank_inc ); +} + +const char* +util_get_charset(const char *file_path) +{ + UCharsetDetector* ucsd; + const UCharsetMatch* ucm; + UErrorCode status = U_ZERO_ERROR; + + const char* charset = NULL; + char *buf = NULL; + FILE* fin =0; + size_t n_size = 0; + + fin = fopen(file_path, "r"); + if (!fin) + { + secure_debug_error("fail to open file %s\n", file_path); + return NULL; + } + + ucsd = ucsdet_open( &status ); + if( U_FAILURE(status) ) { + debug_error("fail to ucsdet_open\n"); + goto done; + } + + ucsdet_enableInputFilter( ucsd, TRUE ); + + buf = g_malloc(1024*1024); + if (!buf) + { + debug_error("fail to alloc\n"); + goto done; + } + + n_size = fread( buf, 1, 1024*1024, fin ); + + if (!n_size) + goto done; + + ucsdet_setText( ucsd, buf, strlen(buf), &status ); + if( U_FAILURE(status) ) { + debug_error("fail to ucsdet_setText\n"); + goto done; + } + + ucm = ucsdet_detect( ucsd, &status ); + if( U_FAILURE(status) ) { + debug_error("fail to ucsdet_detect\n"); + goto done; + } + + charset = ucsdet_getName( ucm, &status ); + if( U_FAILURE(status) ) { + debug_error("fail to ucsdet_getName\n"); + goto done; + } + +done: + if(fin) + fclose(fin); + + if(ucsd) + ucsdet_close( ucsd ); + + if (buf) + g_free(buf); + + return charset; +} + +int +util_get_is_connected_external_display(void) +{ + int is_connected_hdmi = -1; + int is_connected_mirroring = -1; + +#if 0 + if (vconf_get_int(VCONFKEY_SYSMAN_HDMI, &is_connected_hdmi)) + debug_error("[hdmi]vconf_set_int FAIL"); + if (vconf_get_int(VCONFKEY_SCREEN_MIRRORING_STATE, &is_connected_mirroring)) + debug_error("[mirroring]vconf_set_int FAIL"); + + /* if conneted with external display */ + if (is_connected_mirroring == VCONFKEY_SCREEN_MIRRORING_CONNECTED) { + debug_warning ("connected with mirroring display"); + return MMPLAYER_DISPLAY_MIRRORING_ACTIVE; + } + if (is_connected_hdmi == VCONFKEY_SYSMAN_HDMI_CONNECTED) { + debug_warning ("connected with external display"); + return MMPLAYER_DISPLAY_HDMI_ACTIVE; + } + if ((is_connected_mirroring == VCONFKEY_SCREEN_MIRRORING_ACTIVATED || is_connected_mirroring == VCONFKEY_SCREEN_MIRRORING_DEACTIVATED) && is_connected_hdmi == VCONFKEY_SYSMAN_HDMI_DISCONNECTED) { + debug_warning ("non-connected status"); + return MMPLAYER_DISPLAY_NULL; + } +#endif + debug_error ("it is not registered (%d, %d)", is_connected_mirroring, is_connected_hdmi); + return -1; +} + +int util_get_pixtype(unsigned int fourcc) +{ + int pixtype = MM_PIXEL_FORMAT_INVALID; + + /* + char *pfourcc = (char*)&fourcc; + + debug_log("fourcc(%c%c%c%c)", + pfourcc[0], pfourcc[1], pfourcc[2], pfourcc[3]); + */ + + + switch (fourcc) { + case GST_MAKE_FOURCC ('S', 'N', '1', '2'): + case GST_MAKE_FOURCC ('N', 'V', '1', '2'): + pixtype = MM_PIXEL_FORMAT_NV12; + break; + case GST_MAKE_FOURCC ('S', 'T', '1', '2'): + pixtype = MM_PIXEL_FORMAT_NV12T; + break; + case GST_MAKE_FOURCC ('S', 'N', '2', '1'): + case GST_MAKE_FOURCC ('N', 'V', '2', '1'): + pixtype = MM_PIXEL_FORMAT_NV21; + break; + case GST_MAKE_FOURCC ('S', 'U', 'Y', 'V'): + case GST_MAKE_FOURCC ('Y', 'U', 'Y', 'V'): + case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'): + pixtype = MM_PIXEL_FORMAT_YUYV; + break; + case GST_MAKE_FOURCC ('S', 'Y', 'V', 'Y'): + case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'): + pixtype = MM_PIXEL_FORMAT_UYVY; + break; + case GST_MAKE_FOURCC ('S', '4', '2', '0'): + case GST_MAKE_FOURCC ('I', '4', '2', '0'): + pixtype = MM_PIXEL_FORMAT_I420; + break; + case GST_MAKE_FOURCC ('Y', 'V', '1', '2'): + pixtype = MM_PIXEL_FORMAT_YV12; + break; + case GST_MAKE_FOURCC ('4', '2', '2', 'P'): + pixtype = MM_PIXEL_FORMAT_422P; + break; + case GST_MAKE_FOURCC ('R', 'G', 'B', 'P'): + pixtype = MM_PIXEL_FORMAT_RGB565; + break; + case GST_MAKE_FOURCC ('R', 'G', 'B', '3'): + pixtype = MM_PIXEL_FORMAT_RGB888; + break; + case GST_MAKE_FOURCC ('A', 'R', 'G', 'B'): + case GST_MAKE_FOURCC ('x', 'R', 'G', 'B'): + pixtype = MM_PIXEL_FORMAT_ARGB; + break; + case GST_MAKE_FOURCC ('B', 'G', 'R', 'A'): + case GST_MAKE_FOURCC ('B', 'G', 'R', 'x'): + case GST_MAKE_FOURCC ('S', 'R', '3', '2'): + pixtype = MM_PIXEL_FORMAT_RGBA; + break; + case GST_MAKE_FOURCC ('J', 'P', 'E', 'G'): + case GST_MAKE_FOURCC ('P', 'N', 'G', ' '): + pixtype = MM_PIXEL_FORMAT_ENCODED; + break; + /*FIXME*/ + case GST_MAKE_FOURCC ('I', 'T', 'L', 'V'): + pixtype = MM_PIXEL_FORMAT_ITLV_JPEG_UYVY; + break; + default: + debug_error("Not supported fourcc type(%c%c%c%c)", + fourcc, fourcc>>8, fourcc>>16, fourcc>>24); + pixtype = MM_PIXEL_FORMAT_INVALID; + break; + } + + return pixtype; +}