4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
42 #include "mm_player_priv.h"
43 #include "mm_player_ini.h"
44 #include "mm_player_attrs.h"
45 #include "mm_player_capture.h"
46 #include "mm_player_utils.h"
47 #include "mm_player_tracks.h"
48 #include "mm_player_360.h"
49 #include "mm_player_gst.h"
51 #include <system_info.h>
52 #include <sound_manager.h>
53 #include <gst/allocators/gsttizenmemory.h>
54 #include <tbm_surface_internal.h>
56 /*===========================================================================================
58 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
60 ========================================================================================== */
62 /*---------------------------------------------------------------------------
63 | GLOBAL CONSTANT DEFINITIONS: |
64 ---------------------------------------------------------------------------*/
66 /*---------------------------------------------------------------------------
67 | IMPORTED VARIABLE DECLARATIONS: |
68 ---------------------------------------------------------------------------*/
70 /*---------------------------------------------------------------------------
71 | IMPORTED FUNCTION DECLARATIONS: |
72 ---------------------------------------------------------------------------*/
74 /*---------------------------------------------------------------------------
76 ---------------------------------------------------------------------------*/
77 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
78 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
80 #define MM_VOLUME_FACTOR_DEFAULT 1.0
81 #define MM_VOLUME_FACTOR_MIN 0
82 #define MM_VOLUME_FACTOR_MAX 1.0
84 /* Don't need to sleep for sound fadeout
85 * fadeout related fucntion will be deleted(Deprecated)
87 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
89 #define DEFAULT_PLAYBACK_RATE 1.0
90 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
92 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
93 (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
94 (player->ini.http_use_file_buffer) && \
95 (player->http_file_buffering_path) && \
96 (strlen(player->http_file_buffering_path) > 0))
98 #define PLAYER_DISPLAY_MODE_DST_ROI 5
100 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
102 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
103 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
104 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
105 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
107 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
108 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
110 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
112 /*---------------------------------------------------------------------------
113 | LOCAL CONSTANT DEFINITIONS: |
114 ---------------------------------------------------------------------------*/
116 /*---------------------------------------------------------------------------
117 | LOCAL DATA TYPE DEFINITIONS: |
118 ---------------------------------------------------------------------------*/
120 /*---------------------------------------------------------------------------
121 | GLOBAL VARIABLE DEFINITIONS: |
122 ---------------------------------------------------------------------------*/
124 /*---------------------------------------------------------------------------
125 | LOCAL VARIABLE DEFINITIONS: |
126 ---------------------------------------------------------------------------*/
127 static sound_stream_info_h stream_info;
129 /*---------------------------------------------------------------------------
130 | LOCAL FUNCTION PROTOTYPES: |
131 ---------------------------------------------------------------------------*/
132 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
133 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
134 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
135 static int __mmplayer_gst_create_video_sink_bin(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
136 static int __mmplayer_gst_create_audio_sink_bin(mm_player_t* player);
137 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
139 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
140 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
141 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
142 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
143 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
144 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
145 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
146 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
147 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
148 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
149 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
151 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
152 static void __mmplayer_release_misc(mm_player_t* player);
153 static void __mmplayer_release_misc_post(mm_player_t* player);
154 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
155 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
156 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
158 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
160 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
161 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
162 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
163 static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
164 static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
165 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
166 static gpointer __mmplayer_gapless_play_thread(gpointer data);
167 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
168 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
169 static void __mmplayer_release_dump_list(GList *dump_list);
170 static int __mmplayer_gst_realize(mm_player_t* player);
171 static int __mmplayer_gst_unrealize(mm_player_t* player);
172 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
173 static int __mmplayer_gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
176 static gboolean __mmplayer_verify_gapless_play_path(mm_player_t *player);
177 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
178 static void __mmplayer_check_pipeline(mm_player_t* player);
179 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
180 static void __mmplayer_deactivate_old_path(mm_player_t *player);
181 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
182 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
183 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
184 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
185 static void __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
186 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
187 static gboolean __mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs);
188 static gboolean __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs);
189 static gboolean __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs);
190 static gboolean __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs);
192 static void __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile* data, const char *uri, int uri_type);
193 static int __mmplayer_set_mem_uri(MMPlayerParseProfile* data, char *path, void *param);
194 static int __mmplayer_set_file_uri(MMPlayerParseProfile* data, const char *uri);
196 static MMPlayerVideoStreamDataType* __mmplayer_create_stream_from_pad(GstPad *pad);
197 static void __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem);
198 static gboolean __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream);
199 static gboolean __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem);
201 static void __mmplayer_set_pause_state(mm_player_t *player);
202 static void __mmplayer_set_playing_state(mm_player_t *player);
203 /*===========================================================================================
205 | FUNCTION DEFINITIONS |
207 ========================================================================================== */
211 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
215 count = gst_tag_list_get_tag_size(list, tag);
217 LOGD("count = %d", count);
219 for (i = 0; i < count; i++) {
222 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
223 if (!gst_tag_list_get_string_index(list, tag, i, &str))
224 g_assert_not_reached();
226 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
229 g_print(" %15s: %s\n", gst_tag_get_nick(tag), str);
231 g_print(" : %s\n", str);
238 /* This function should be called after the pipeline goes PAUSED or higher
241 __mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
243 static gboolean has_duration = FALSE;
244 static gboolean has_video_attrs = FALSE;
245 static gboolean has_audio_attrs = FALSE;
246 static gboolean has_bitrate = FALSE;
247 gboolean missing_only = FALSE;
248 gboolean all = FALSE;
249 MMHandleType attrs = 0;
253 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
255 /* check player state here */
256 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
257 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
258 /* give warning now only */
259 LOGW("be careful. content attributes may not available in this state ");
262 /* get content attribute first */
263 attrs = MMPLAYER_GET_ATTRS(player);
265 LOGE("cannot get content attribute");
269 /* get update flag */
271 if (flag & ATTR_MISSING_ONLY) {
273 LOGD("updating missed attr only");
276 if (flag & ATTR_ALL) {
278 has_duration = FALSE;
279 has_video_attrs = FALSE;
280 has_audio_attrs = FALSE;
283 LOGD("updating all attrs");
286 if (missing_only && all) {
287 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
288 missing_only = FALSE;
291 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
292 has_duration = __mmplayer_update_duration_attrs(player, attrs);
294 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
295 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
297 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
298 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
300 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
301 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
304 if (mm_attrs_commit_all(attrs)) {
305 LOGE("failed to update attributes\n");
314 MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
316 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
320 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
322 player->pipeline->mainbin &&
323 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
324 STREAMING_SERVICE_NONE);
326 /* streaming service type if streaming */
327 if (!MMPLAYER_IS_STREAMING(player))
328 return STREAMING_SERVICE_NONE;
330 streaming_type = (player->duration == 0) ?
331 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
333 switch (streaming_type) {
334 case STREAMING_SERVICE_LIVE:
335 LOGD("it's live streaming");
337 case STREAMING_SERVICE_VOD:
338 LOGD("it's vod streaming");
341 LOGE("should not get here");
347 return streaming_type;
351 /* this function sets the player state and also report
352 * it to applicaton by calling callback function
355 __mmplayer_set_state(mm_player_t *player, int state)
357 MMMessageParamType msg = {0, };
359 MMPLAYER_RETURN_IF_FAIL(player);
361 if (MMPLAYER_CURRENT_STATE(player) == state) {
362 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
363 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
367 /* update player states */
368 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
369 MMPLAYER_CURRENT_STATE(player) = state;
371 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
372 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
375 MMPLAYER_PRINT_STATE(player);
377 switch (MMPLAYER_CURRENT_STATE(player)) {
378 case MM_PLAYER_STATE_NULL:
379 case MM_PLAYER_STATE_READY:
381 case MM_PLAYER_STATE_PAUSED:
382 __mmplayer_set_pause_state(player);
384 case MM_PLAYER_STATE_PLAYING:
385 __mmplayer_set_playing_state(player);
387 case MM_PLAYER_STATE_NONE:
389 LOGW("invalid target state, there is nothing to do.\n");
394 /* post message to application */
395 if (MMPLAYER_TARGET_STATE(player) == state) {
396 /* fill the message with state of player */
397 msg.union_type = MM_MSG_UNION_STATE;
398 msg.state.previous = MMPLAYER_PREV_STATE(player);
399 msg.state.current = MMPLAYER_CURRENT_STATE(player);
401 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
403 /* state changed by resource callback */
404 if (player->interrupted_by_resource) {
405 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
406 } else { /* state changed by usecase */
407 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
410 LOGD("intermediate state, do nothing.\n");
411 MMPLAYER_PRINT_STATE(player);
415 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
416 && !player->sent_bos) {
417 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
418 player->sent_bos = TRUE;
425 __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command)
427 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
428 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
430 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
432 //LOGD("incomming command : %d \n", command);
434 current_state = MMPLAYER_CURRENT_STATE(player);
435 pending_state = MMPLAYER_PENDING_STATE(player);
437 MMPLAYER_PRINT_STATE(player);
440 case MMPLAYER_COMMAND_CREATE:
442 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
444 if (current_state == MM_PLAYER_STATE_NULL ||
445 current_state == MM_PLAYER_STATE_READY ||
446 current_state == MM_PLAYER_STATE_PAUSED ||
447 current_state == MM_PLAYER_STATE_PLAYING)
452 case MMPLAYER_COMMAND_DESTROY:
454 /* destroy can called anytime */
456 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
460 case MMPLAYER_COMMAND_REALIZE:
462 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
464 if (pending_state != MM_PLAYER_STATE_NONE) {
467 /* need ready state to realize */
468 if (current_state == MM_PLAYER_STATE_READY)
471 if (current_state != MM_PLAYER_STATE_NULL)
477 case MMPLAYER_COMMAND_UNREALIZE:
479 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
481 if (current_state == MM_PLAYER_STATE_NULL)
486 case MMPLAYER_COMMAND_START:
488 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
490 if (pending_state == MM_PLAYER_STATE_NONE) {
491 if (current_state == MM_PLAYER_STATE_PLAYING)
493 else if (current_state != MM_PLAYER_STATE_READY &&
494 current_state != MM_PLAYER_STATE_PAUSED)
496 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
498 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
499 LOGD("player is going to paused state, just change the pending state as playing");
505 case MMPLAYER_COMMAND_STOP:
507 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
509 if (current_state == MM_PLAYER_STATE_READY)
512 /* need playing/paused state to stop */
513 if (current_state != MM_PLAYER_STATE_PLAYING &&
514 current_state != MM_PLAYER_STATE_PAUSED)
519 case MMPLAYER_COMMAND_PAUSE:
521 if (MMPLAYER_IS_LIVE_STREAMING(player))
524 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
525 goto NOT_COMPLETED_SEEK;
527 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
529 if (pending_state == MM_PLAYER_STATE_NONE) {
530 if (current_state == MM_PLAYER_STATE_PAUSED)
532 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
534 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
536 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
537 if (current_state == MM_PLAYER_STATE_PAUSED)
538 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
545 case MMPLAYER_COMMAND_RESUME:
547 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
548 goto NOT_COMPLETED_SEEK;
550 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
552 if (pending_state == MM_PLAYER_STATE_NONE) {
553 if (current_state == MM_PLAYER_STATE_PLAYING)
555 else if (current_state != MM_PLAYER_STATE_PAUSED)
557 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
559 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
560 LOGD("player is going to paused state, just change the pending state as playing");
569 player->cmd = command;
571 return MM_ERROR_NONE;
574 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
575 MMPLAYER_STATE_GET_NAME(current_state), command);
576 return MM_ERROR_PLAYER_INVALID_STATE;
579 LOGW("not completed seek");
580 return MM_ERROR_PLAYER_DOING_SEEK;
583 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
584 return MM_ERROR_PLAYER_NO_OP;
587 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
588 return MM_ERROR_PLAYER_NO_OP;
591 static gpointer __mmplayer_gapless_play_thread(gpointer data)
593 mm_player_t* player = (mm_player_t*) data;
594 MMPlayerGstElement *mainbin = NULL;
596 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
598 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
599 while (!player->gapless_play_thread_exit) {
600 LOGD("gapless play thread started. waiting for signal.\n");
601 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
603 LOGD("reconfigure pipeline for gapless play.\n");
605 if (player->gapless_play_thread_exit) {
606 if (player->gapless.reconfigure) {
607 player->gapless.reconfigure = false;
608 MMPLAYER_PLAYBACK_UNLOCK(player);
610 LOGD("exiting gapless play thread\n");
614 mainbin = player->pipeline->mainbin;
616 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
617 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
618 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
619 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
620 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
622 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
624 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
630 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
632 GSource *source = NULL;
636 source = g_main_context_find_source_by_id(context, source_id);
638 if (source != NULL) {
639 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
640 g_source_destroy(source);
646 void __mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
648 mm_player_t* player = (mm_player_t*)hplayer;
649 GstMessage *msg = NULL;
650 GQueue *queue = NULL;
653 MMPLAYER_RETURN_IF_FAIL(player);
655 /* disconnecting bus watch */
656 if (player->bus_watcher)
657 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
658 player->bus_watcher = 0;
660 /* destroy the gst bus msg thread */
661 if (player->bus_msg_thread) {
662 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
663 player->bus_msg_thread_exit = TRUE;
664 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
665 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
667 LOGD("gst bus msg thread exit.");
668 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
669 player->bus_msg_thread = NULL;
671 g_mutex_clear(&player->bus_msg_thread_mutex);
672 g_cond_clear(&player->bus_msg_thread_cond);
675 g_mutex_lock(&player->bus_msg_q_lock);
676 queue = player->bus_msg_q;
677 while (!g_queue_is_empty(queue)) {
678 msg = (GstMessage *)g_queue_pop_head(queue);
683 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
684 gst_message_unref(msg);
686 g_mutex_unlock(&player->bus_msg_q_lock);
692 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
694 GstElement* parent = NULL;
696 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
698 /* if we have no fakesink. this meas we are using decodebin which doesn'
699 t need to add extra fakesink */
700 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
703 MMPLAYER_FSINK_LOCK(player);
708 /* get parent of fakesink */
709 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
711 LOGD("fakesink already removed\n");
715 gst_element_set_locked_state(fakesink->gst, TRUE);
717 /* setting the state to NULL never returns async
718 * so no need to wait for completion of state transiton
720 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
721 LOGE("fakesink state change failure!\n");
722 /* FIXIT : should I return here? or try to proceed to next? */
725 /* remove fakesink from it's parent */
726 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
727 LOGE("failed to remove fakesink\n");
729 gst_object_unref(parent);
734 gst_object_unref(parent);
736 LOGD("state-holder removed\n");
738 gst_element_set_locked_state(fakesink->gst, FALSE);
740 MMPLAYER_FSINK_UNLOCK(player);
745 gst_element_set_locked_state(fakesink->gst, FALSE);
747 MMPLAYER_FSINK_UNLOCK(player);
751 static GstPadProbeReturn
752 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
754 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
755 return GST_PAD_PROBE_OK;
759 __mmplayer_gst_selector_update_start_time(mm_player_t* player, MMPlayerTrackType stream_type)
761 gint64 stop_running_time = 0;
762 gint64 position_running_time = 0;
766 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
767 if ((player->gapless.update_segment[idx] == TRUE) ||
768 !(player->selector[idx].event_probe_id)) {
769 /* LOGW("[%d] skip", idx); */
773 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
775 gst_segment_to_running_time(&player->gapless.segment[idx],
776 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
777 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
779 gst_segment_to_running_time(&player->gapless.segment[idx],
780 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
782 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
784 gst_segment_to_running_time(&player->gapless.segment[idx],
785 GST_FORMAT_TIME, player->duration);
788 position_running_time =
789 gst_segment_to_running_time(&player->gapless.segment[idx],
790 GST_FORMAT_TIME, player->gapless.segment[idx].position);
792 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
793 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
795 GST_TIME_ARGS(stop_running_time),
796 GST_TIME_ARGS(position_running_time),
797 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
798 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
800 position_running_time = MAX(position_running_time, stop_running_time);
801 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
802 GST_FORMAT_TIME, player->gapless.segment[idx].start);
803 position_running_time = MAX(0, position_running_time);
804 position = MAX(position, position_running_time);
808 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
809 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
810 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
812 player->gapless.start_time[stream_type] += position;
818 static GstPadProbeReturn
819 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
821 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
822 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
823 mm_player_t *player = (mm_player_t*)data;
824 GstCaps *caps = NULL;
825 GstStructure *str = NULL;
826 const gchar *name = NULL;
827 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
828 gboolean caps_ret = TRUE;
830 if (GST_EVENT_IS_DOWNSTREAM(event) &&
831 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
832 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
833 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
834 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
836 } else if (GST_EVENT_IS_UPSTREAM(event) &&
837 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
841 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
845 if (strstr(name, "audio")) {
846 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
847 } else if (strstr(name, "video")) {
848 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
850 /* text track is not supportable */
851 LOGE("invalid name %s", name);
855 switch (GST_EVENT_TYPE(event)) {
858 /* in case of gapless, drop eos event not to send it to sink */
859 if (player->gapless.reconfigure && !player->msg_posted) {
860 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
861 ret = GST_PAD_PROBE_DROP;
865 case GST_EVENT_STREAM_START:
867 __mmplayer_gst_selector_update_start_time(player, stream_type);
870 case GST_EVENT_FLUSH_STOP:
872 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
873 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
874 player->gapless.start_time[stream_type] = 0;
877 case GST_EVENT_SEGMENT:
882 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
883 gst_event_copy_segment(event, &segment);
885 if (segment.format != GST_FORMAT_TIME)
888 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
889 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
890 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
891 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
892 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
893 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
895 /* keep the all the segment ev to cover the seeking */
896 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
897 player->gapless.update_segment[stream_type] = TRUE;
899 if (!player->gapless.running)
902 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
904 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
906 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
907 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
908 gst_event_unref(event);
909 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
915 gdouble proportion = 0.0;
916 GstClockTimeDiff diff = 0;
917 GstClockTime timestamp = 0;
918 gint64 running_time_diff = -1;
920 GstEvent *tmpev = NULL;
922 running_time_diff = player->gapless.segment[stream_type].base;
924 if (running_time_diff <= 0) /* don't need to adjust */
927 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
928 gst_event_unref(event);
930 if (timestamp < running_time_diff) {
931 LOGW("QOS event from previous group");
932 ret = GST_PAD_PROBE_DROP;
936 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
937 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
938 stream_type, GST_TIME_ARGS(timestamp),
939 GST_TIME_ARGS(running_time_diff),
940 GST_TIME_ARGS(timestamp - running_time_diff));
942 timestamp -= running_time_diff;
944 /* That case is invalid for QoS events */
945 if (diff < 0 && -diff > timestamp) {
946 LOGW("QOS event from previous group");
947 ret = GST_PAD_PROBE_DROP;
951 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
952 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
962 gst_caps_unref(caps);
966 /* create fakesink for audio or video path witout audiobin or videobin */
968 __mmplayer_gst_make_fakesink(mm_player_t *player, GstPad *pad, const gchar *name)
970 GstElement *pipeline = NULL;
971 GstElement *fakesink = NULL;
972 GstPad *sinkpad = NULL;
975 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
977 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
980 fakesink = gst_element_factory_make("fakesink", NULL);
981 if (fakesink == NULL) {
982 LOGE("failed to create fakesink");
986 /* store it as it's sink element */
987 __mmplayer_add_sink(player, fakesink);
989 gst_bin_add(GST_BIN(pipeline), fakesink);
992 sinkpad = gst_element_get_static_pad(fakesink, "sink");
994 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
996 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
997 LOGE("failed to link fakesink");
998 gst_object_unref(GST_OBJECT(fakesink));
1002 if (strstr(name, "video")) {
1003 if (player->v_stream_caps) {
1004 gst_caps_unref(player->v_stream_caps);
1005 player->v_stream_caps = NULL;
1007 if (player->ini.set_dump_element_flag)
1008 __mmplayer_add_dump_buffer_probe(player, fakesink);
1011 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1012 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1016 gst_object_unref(GST_OBJECT(sinkpad));
1023 __mmplayer_gst_make_selector(mm_player_t *player, enum MainElementID elem_idx, MMPlayerTrackType stream_type)
1025 GstElement *pipeline = NULL;
1026 GstElement *selector = NULL;
1027 GstPad *srcpad = NULL;
1030 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1032 selector = gst_element_factory_make("input-selector", NULL);
1034 LOGE("failed to create input-selector");
1037 g_object_set(selector, "sync-streams", TRUE, NULL);
1039 player->pipeline->mainbin[elem_idx].id = elem_idx;
1040 player->pipeline->mainbin[elem_idx].gst = selector;
1042 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1044 srcpad = gst_element_get_static_pad(selector, "src");
1046 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1047 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1048 __mmplayer_gst_selector_blocked, NULL, NULL);
1049 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1050 __mmplayer_gst_selector_event_probe, player, NULL);
1052 gst_element_set_state(selector, GST_STATE_PAUSED);
1054 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1055 gst_bin_add(GST_BIN(pipeline), selector);
1062 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1064 mm_player_t *player = NULL;
1065 GstElement *selector = NULL;
1066 GstCaps *caps = NULL;
1067 GstStructure *str = NULL;
1068 const gchar *name = NULL;
1069 GstPad *sinkpad = NULL;
1070 gboolean first_track = FALSE;
1071 gboolean caps_ret = TRUE;
1073 enum MainElementID elem_idx = MMPLAYER_M_NUM;
1074 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1077 player = (mm_player_t*)data;
1080 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1081 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1083 LOGD("pad-added signal handling");
1085 /* get mimetype from caps */
1086 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1090 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1091 /* LOGD("detected mimetype : %s", name); */
1093 if (strstr(name, "video")) {
1095 gchar *caps_str = NULL;
1097 caps_str = gst_caps_to_string(caps);
1098 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1099 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1100 player->set_mode.video_zc = TRUE;
1102 MMPLAYER_FREEIF(caps_str);
1104 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1105 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1107 LOGD("surface type : %d", stype);
1109 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1110 __mmplayer_gst_create_sinkbin(elem, pad, player);
1114 /* in case of exporting video frame, it requires the 360 video filter.
1115 * it will be handled in _no_more_pads(). */
1116 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)){
1117 __mmplayer_gst_make_fakesink(player, pad, name);
1121 LOGD("video selector is required");
1122 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1123 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1124 } else if (strstr(name, "audio")) {
1125 gint samplerate = 0;
1128 gst_structure_get_int(str, "rate", &samplerate);
1129 gst_structure_get_int(str, "channels", &channels);
1131 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1132 __mmplayer_gst_create_sinkbin(elem, pad, player);
1136 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1137 __mmplayer_gst_make_fakesink(player, pad, name);
1141 LOGD("audio selector is required");
1142 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1143 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1145 } else if (strstr(name, "text")) {
1146 LOGD("text selector is required");
1147 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1148 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1150 LOGE("invalid caps info");
1154 /* check selector and create it */
1155 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1156 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1161 LOGD("input-selector is already created.");
1165 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1167 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1169 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1170 LOGE("failed to link selector");
1171 gst_object_unref(GST_OBJECT(selector));
1176 LOGD("this track will be activated");
1177 g_object_set(selector, "active-pad", sinkpad, NULL);
1180 __mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1186 gst_caps_unref(caps);
1189 gst_object_unref(GST_OBJECT(sinkpad));
1196 static gboolean __mmplayer_create_sink_path(mm_player_t* player, GstElement* selector, MMPlayerTrackType type)
1198 GstPad* srcpad = NULL;
1201 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1203 LOGD("type %d", type);
1206 LOGD("there is no %d track", type);
1210 srcpad = gst_element_get_static_pad(selector, "src");
1212 LOGE("failed to get srcpad from selector");
1216 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1218 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1220 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1221 if (player->selector[type].block_id) {
1222 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1223 player->selector[type].block_id = 0;
1227 gst_object_unref(GST_OBJECT(srcpad));
1235 static void __mmplayer_set_decode_track_info(mm_player_t* player, MMPlayerTrackType type)
1237 MMHandleType attrs = 0;
1238 gint active_index = 0;
1241 MMPLAYER_RETURN_IF_FAIL(player);
1243 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1245 /* change track to active pad */
1246 active_index = player->selector[type].active_pad_index;
1247 if ((active_index != DEFAULT_TRACK) &&
1248 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1249 LOGW("failed to change %d type track to %d", type, active_index);
1250 player->selector[type].active_pad_index = DEFAULT_TRACK;
1254 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1255 attrs = MMPLAYER_GET_ATTRS(player);
1257 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1258 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1260 if (mm_attrs_commit_all(attrs))
1261 LOGW("failed to commit attrs.");
1263 LOGW("cannot get content attribute");
1271 static gboolean __mmplayer_create_audio_sink_path(mm_player_t* player, GstElement* audio_selector)
1274 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1276 if (!audio_selector) {
1277 LOGD("there is no audio track");
1279 /* in case the source is changed, output can be changed. */
1280 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1281 LOGD("remove previous audiobin if it exist");
1283 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1284 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1286 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1287 MMPLAYER_FREEIF(player->pipeline->audiobin);
1290 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1291 __mmplayer_pipeline_complete(NULL, player);
1296 /* apply the audio track information */
1297 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1299 /* create audio sink path */
1300 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1301 LOGE("failed to create audio sink path");
1309 static gboolean __mmplayer_create_text_sink_path(mm_player_t* player, GstElement* text_selector)
1312 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1314 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1315 LOGD("text path is not supproted");
1319 /* apply the text track information */
1320 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1322 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1323 player->has_closed_caption = TRUE;
1325 /* create text decode path */
1326 player->no_more_pad = TRUE;
1328 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1329 LOGE("failed to create text sink path");
1338 __mmplayer_gst_set_queue2_buffering(mm_player_t *player)
1340 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
1342 gint init_buffering_time = 0;
1343 guint buffer_bytes = 0;
1344 gint64 dur_bytes = 0L;
1347 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1348 player->pipeline->mainbin && player->streamer, FALSE);
1350 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
1351 buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
1353 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
1354 LOGD("pre buffer time: %d ms, buffer size : %d", init_buffering_time, buffer_bytes);
1356 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
1358 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1359 LOGE("fail to get duration.");
1361 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1362 * use file information was already set on Q2 when it was created. */
1363 __mm_player_streaming_set_queue2(player->streamer,
1364 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1365 TRUE, /* use_buffering */
1367 init_buffering_time,
1368 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1370 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1377 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1379 mm_player_t *player = NULL;
1380 GstElement *video_selector = NULL;
1381 GstElement *audio_selector = NULL;
1382 GstElement *text_selector = NULL;
1385 player = (mm_player_t*) data;
1387 LOGD("no-more-pad signal handling");
1389 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1390 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1391 LOGW("player is shutting down");
1395 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1396 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1397 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1398 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1399 LOGE("failed to set queue2 buffering");
1404 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1405 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1406 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1408 /* create video path followed by video-select */
1409 if (video_selector && !audio_selector && !text_selector)
1410 player->no_more_pad = TRUE;
1412 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1415 /* create audio path followed by audio-select */
1416 if (audio_selector && !text_selector)
1417 player->no_more_pad = TRUE;
1419 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1422 /* create text path followed by text-select */
1423 __mmplayer_create_text_sink_path(player, text_selector);
1426 if (player->gapless.reconfigure) {
1427 player->gapless.reconfigure = FALSE;
1428 MMPLAYER_PLAYBACK_UNLOCK(player);
1435 __mmplayer_gst_add_sinkbin_to_pipeline(mm_player_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1437 gboolean ret = FALSE;
1438 GstElement *pipeline = NULL;
1439 GstPad *sinkpad = NULL;
1442 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1443 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1445 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1447 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1449 LOGE("failed to get pad from sinkbin");
1455 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1456 LOGE("failed to link sinkbin for reusing");
1457 goto EXIT; /* exit either pass or fail */
1461 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1462 LOGE("failed to set state(READY) to sinkbin");
1467 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1468 LOGE("failed to add sinkbin to pipeline");
1473 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1474 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1479 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1480 LOGE("failed to set state(PAUSED) to sinkbin");
1489 gst_object_unref(GST_OBJECT(sinkpad));
1496 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1498 mm_player_t *player = NULL;
1499 MMHandleType attrs = 0;
1500 GstCaps *caps = NULL;
1501 gchar *caps_str = NULL;
1502 GstStructure *str = NULL;
1503 const gchar *name = NULL;
1504 GstElement *sinkbin = NULL;
1505 gboolean reusing = FALSE;
1506 gboolean caps_ret = TRUE;
1507 gchar *sink_pad_name = "sink";
1510 player = (mm_player_t*) data;
1513 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1514 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1516 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1520 caps_str = gst_caps_to_string(caps);
1522 /* LOGD("detected mimetype : %s", name); */
1523 if (strstr(name, "audio")) {
1524 if (player->pipeline->audiobin == NULL) {
1525 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1526 LOGE("failed to create audiobin. continuing without audio");
1530 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1531 LOGD("creating audiobin success");
1534 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1535 LOGD("reusing audiobin");
1536 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
1538 } else if (strstr(name, "video")) {
1539 /* 1. zero copy is updated at _decode_pad_added()
1540 * 2. NULL surface type is handled in _decode_pad_added() */
1541 LOGD("zero copy %d", player->set_mode.video_zc);
1542 if (player->pipeline->videobin == NULL) {
1543 int surface_type = 0;
1544 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1545 LOGD("display_surface_type (%d)", surface_type);
1547 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) {
1548 LOGD("mark video overlay for acquire");
1549 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1550 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1551 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1552 &player->video_overlay_resource)
1553 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1554 LOGE("could not mark video_overlay resource for acquire");
1559 player->interrupted_by_resource = FALSE;
1561 if (mm_resource_manager_commit(player->resource_manager) !=
1562 MM_RESOURCE_MANAGER_ERROR_NONE) {
1563 LOGE("could not acquire resources for video playing");
1567 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1568 LOGE("failed to create videobin. continuing without video");
1572 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1573 LOGD("creating videosink bin success");
1576 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1577 LOGD("re-using videobin");
1578 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
1580 } else if (strstr(name, "text")) {
1581 if (player->pipeline->textbin == NULL) {
1582 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1583 LOGE("failed to create text sink bin. continuing without text");
1587 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1588 player->textsink_linked = 1;
1589 LOGD("creating textsink bin success");
1591 if (!player->textsink_linked) {
1592 LOGD("re-using textbin");
1594 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1595 player->textsink_linked = 1;
1597 /* linked textbin exist which means that the external subtitle path exist already */
1598 LOGW("ignoring internal subtutle since external subtitle is available");
1601 sink_pad_name = "text_sink";
1603 LOGW("unknown mime type %s, ignoring it", name);
1607 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1610 LOGD("[handle: %p] success to create and link sink bin", player);
1612 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1613 * streaming task. if the task blocked, then buffer will not flow to the next element
1614 *(autoplugging element). so this is special hack for streaming. please try to remove it
1616 /* dec stream count. we can remove fakesink if it's zero */
1617 if (player->num_dynamic_pad)
1618 player->num_dynamic_pad--;
1620 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1622 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1623 __mmplayer_pipeline_complete(NULL, player);
1627 MMPLAYER_FREEIF(caps_str);
1630 gst_caps_unref(caps);
1632 /* flusing out new attributes */
1633 if (mm_attrs_commit_all(attrs))
1634 LOGE("failed to comit attributes");
1640 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int display_angle, int orientation, int *value)
1642 int required_angle = 0; /* Angle required for straight view */
1643 int rotation_angle = 0;
1645 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1646 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1648 /* Counter clockwise */
1649 switch (orientation) {
1654 required_angle = 270;
1657 required_angle = 180;
1660 required_angle = 90;
1664 rotation_angle = display_angle + required_angle;
1665 if (rotation_angle >= 360)
1666 rotation_angle -= 360;
1668 /* chech if supported or not */
1669 if (rotation_angle % 90) {
1670 LOGD("not supported rotation angle = %d", rotation_angle);
1674 switch (rotation_angle) {
1676 *value = MM_DISPLAY_ROTATION_NONE;
1679 *value = MM_DISPLAY_ROTATION_90;
1682 *value = MM_DISPLAY_ROTATION_180;
1685 *value = MM_DISPLAY_ROTATION_270;
1689 LOGD("setting rotation property value : %d", *value);
1695 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
1697 /* check video sinkbin is created */
1698 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1700 player->pipeline->videobin &&
1701 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1702 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1703 MM_ERROR_PLAYER_NOT_INITIALIZED);
1705 return MM_ERROR_NONE;
1709 __mmplayer_get_video_angle(mm_player_t* player, int *display_angle, int *orientation)
1711 int display_rotation = 0;
1712 gchar *org_orient = NULL;
1713 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1716 LOGE("cannot get content attribute");
1717 return MM_ERROR_PLAYER_INTERNAL;
1720 if (display_angle) {
1721 /* update user roation */
1722 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1724 /* Counter clockwise */
1725 switch (display_rotation) {
1726 case MM_DISPLAY_ROTATION_NONE:
1729 case MM_DISPLAY_ROTATION_90:
1730 *display_angle = 90;
1732 case MM_DISPLAY_ROTATION_180:
1733 *display_angle = 180;
1735 case MM_DISPLAY_ROTATION_270:
1736 *display_angle = 270;
1739 LOGW("wrong angle type : %d", display_rotation);
1742 LOGD("check user angle: %d", *display_angle);
1746 /* Counter clockwise */
1747 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1750 if (!strcmp(org_orient, "rotate-90"))
1752 else if (!strcmp(org_orient, "rotate-180"))
1754 else if (!strcmp(org_orient, "rotate-270"))
1757 LOGD("original rotation is %s", org_orient);
1759 LOGD("content_video_orientation get fail");
1762 LOGD("check orientation: %d", *orientation);
1765 return MM_ERROR_NONE;
1769 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
1771 int rotation_value = 0;
1772 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1773 int display_angle = 0;
1776 /* check video sinkbin is created */
1777 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1780 __mmplayer_get_video_angle(player, &display_angle, &orientations);
1782 /* get rotation value to set */
1783 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1784 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1785 LOGD("set video param : rotate %d", rotation_value);
1789 __mmplayer_video_param_set_display_visible(mm_player_t* player)
1791 MMHandleType attrs = 0;
1795 /* check video sinkbin is created */
1796 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1799 attrs = MMPLAYER_GET_ATTRS(player);
1800 MMPLAYER_RETURN_IF_FAIL(attrs);
1802 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1803 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1804 LOGD("set video param : visible %d", visible);
1808 __mmplayer_video_param_set_display_method(mm_player_t* player)
1810 MMHandleType attrs = 0;
1811 int display_method = 0;
1814 /* check video sinkbin is created */
1815 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1818 attrs = MMPLAYER_GET_ATTRS(player);
1819 MMPLAYER_RETURN_IF_FAIL(attrs);
1821 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1822 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1823 LOGD("set video param : method %d", display_method);
1826 __mmplayer_video_param_set_video_roi_area(mm_player_t* player)
1828 MMHandleType attrs = 0;
1829 void *handle = NULL;
1832 /* check video sinkbin is created */
1833 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1834 LOGW("There is no video sink");
1838 attrs = MMPLAYER_GET_ATTRS(player);
1839 MMPLAYER_RETURN_IF_FAIL(attrs);
1840 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1842 gst_video_overlay_set_video_roi_area(
1843 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1844 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1845 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1846 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1851 __mmplayer_video_param_set_roi_area(mm_player_t* player)
1853 MMHandleType attrs = 0;
1854 void *handle = NULL;
1858 int win_roi_width = 0;
1859 int win_roi_height = 0;
1862 /* check video sinkbin is created */
1863 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1864 LOGW("There is no video sink");
1868 attrs = MMPLAYER_GET_ATTRS(player);
1869 MMPLAYER_RETURN_IF_FAIL(attrs);
1871 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1874 /* It should be set after setting window */
1875 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1876 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1877 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1878 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1880 /* After setting window handle, set display roi area */
1881 gst_video_overlay_set_display_roi_area(
1882 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1883 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1884 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1885 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1889 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
1891 MMHandleType attrs = 0;
1892 void *handle = NULL;
1894 /* check video sinkbin is created */
1895 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1898 attrs = MMPLAYER_GET_ATTRS(player);
1899 MMPLAYER_RETURN_IF_FAIL(attrs);
1901 /* common case if using overlay surface */
1902 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1905 /* default is using wl_surface_id */
1906 unsigned int wl_surface_id = 0;
1907 wl_surface_id = *(int*)handle;
1908 LOGD("set video param : wl_surface_id %d", wl_surface_id);
1909 gst_video_overlay_set_wl_window_wl_surface_id(
1910 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1913 /* FIXIT : is it error case? */
1914 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1919 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
1921 bool update_all_param = FALSE;
1924 /* check video sinkbin is created */
1925 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1926 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1928 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1929 LOGE("can not find tizenwlsink");
1930 return MM_ERROR_PLAYER_INTERNAL;
1933 LOGD("param_name : %s", param_name);
1934 if (!g_strcmp0(param_name, "update_all_param"))
1935 update_all_param = TRUE;
1937 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1938 __mmplayer_video_param_set_display_overlay(player);
1939 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1940 __mmplayer_video_param_set_display_method(player);
1941 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1942 __mmplayer_video_param_set_display_visible(player);
1943 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1944 __mmplayer_video_param_set_display_rotation(player);
1945 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
1946 __mmplayer_video_param_set_roi_area(player);
1947 if (update_all_param)
1948 __mmplayer_video_param_set_video_roi_area(player);
1950 return MM_ERROR_NONE;
1954 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
1956 MMHandleType attrs = 0;
1957 int surface_type = 0;
1958 int ret = MM_ERROR_NONE;
1962 /* check video sinkbin is created */
1963 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1964 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1966 attrs = MMPLAYER_GET_ATTRS(player);
1968 LOGE("cannot get content attribute");
1969 return MM_ERROR_PLAYER_INTERNAL;
1971 LOGD("param_name : %s", param_name);
1973 /* update display surface */
1974 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
1975 LOGD("check display surface type attribute: %d", surface_type);
1977 /* configuring display */
1978 switch (surface_type) {
1979 case MM_DISPLAY_SURFACE_OVERLAY:
1981 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
1982 if (ret != MM_ERROR_NONE)
1990 return MM_ERROR_NONE;
1994 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
1996 gboolean disable_overlay = FALSE;
1997 mm_player_t* player = (mm_player_t*) hplayer;
1998 int ret = MM_ERROR_NONE;
2001 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2002 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2003 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2004 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2006 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2007 LOGW("Display control is not supported");
2008 return MM_ERROR_PLAYER_INTERNAL;
2011 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2013 if (audio_only == (bool)disable_overlay) {
2014 LOGE("It's the same with current setting: (%d)", audio_only);
2015 return MM_ERROR_NONE;
2019 LOGE("disable overlay");
2020 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2022 /* release overlay resource */
2023 if (player->video_overlay_resource != NULL) {
2024 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2025 player->video_overlay_resource);
2026 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2027 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
2030 player->video_overlay_resource = NULL;
2033 ret = mm_resource_manager_commit(player->resource_manager);
2034 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2035 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
2039 /* mark video overlay for acquire */
2040 if (player->video_overlay_resource == NULL) {
2041 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2042 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2043 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2044 &player->video_overlay_resource);
2045 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2046 LOGE("could not prepare for video_overlay resource\n");
2051 player->interrupted_by_resource = FALSE;
2052 /* acquire resources for video overlay */
2053 ret = mm_resource_manager_commit(player->resource_manager);
2054 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2055 LOGE("could not acquire resources for video playing\n");
2059 LOGD("enable overlay");
2060 __mmplayer_video_param_set_display_overlay(player);
2061 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2066 return MM_ERROR_NONE;
2070 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2072 mm_player_t* player = (mm_player_t*) hplayer;
2073 gboolean disable_overlay = FALSE;
2077 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2078 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2079 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2080 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2081 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2083 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2084 LOGW("Display control is not supported");
2085 return MM_ERROR_PLAYER_INTERNAL;
2088 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2090 *paudio_only = (bool)(disable_overlay);
2092 LOGD("audio_only : %d", *paudio_only);
2096 return MM_ERROR_NONE;
2100 __mmplayer_gst_element_link_bucket(GList* element_bucket)
2102 GList* bucket = element_bucket;
2103 MMPlayerGstElement* element = NULL;
2104 MMPlayerGstElement* prv_element = NULL;
2105 gint successful_link_count = 0;
2109 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2111 prv_element = (MMPlayerGstElement*)bucket->data;
2112 bucket = bucket->next;
2114 for (; bucket; bucket = bucket->next) {
2115 element = (MMPlayerGstElement*)bucket->data;
2117 if (element && element->gst) {
2118 if (prv_element && prv_element->gst) {
2119 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2120 LOGD("linking [%s] to [%s] success\n",
2121 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2122 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2123 successful_link_count++;
2125 LOGD("linking [%s] to [%s] failed\n",
2126 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2127 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2133 prv_element = element;
2138 return successful_link_count;
2142 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
2144 GList* bucket = element_bucket;
2145 MMPlayerGstElement* element = NULL;
2146 int successful_add_count = 0;
2150 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2151 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2153 for (; bucket; bucket = bucket->next) {
2154 element = (MMPlayerGstElement*)bucket->data;
2156 if (element && element->gst) {
2157 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2158 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
2159 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2160 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2163 successful_add_count++;
2169 return successful_add_count;
2172 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2174 mm_player_t *player = (mm_player_t*) data;
2175 GstCaps *caps = NULL;
2176 GstStructure *str = NULL;
2178 gboolean caps_ret = TRUE;
2182 MMPLAYER_RETURN_IF_FAIL(pad);
2183 MMPLAYER_RETURN_IF_FAIL(unused);
2184 MMPLAYER_RETURN_IF_FAIL(data);
2186 caps = gst_pad_get_current_caps(pad);
2190 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2194 LOGD("name = %s", name);
2196 if (strstr(name, "audio")) {
2197 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2199 if (player->audio_stream_changed_cb) {
2200 LOGE("call the audio stream changed cb");
2201 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2203 } else if (strstr(name, "video")) {
2204 if ((name = gst_structure_get_string(str, "format")))
2205 player->set_mode.video_zc = name[0] == 'S';
2207 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2209 if (player->video_stream_changed_cb) {
2210 LOGE("call the video stream changed cb");
2211 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2214 LOGW("invalid caps info");
2219 gst_caps_unref(caps);
2229 * This function is to create audio pipeline for playing.
2231 * @param player [in] handle of player
2233 * @return This function returns zero on success.
2235 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_sink_bin
2237 /* macro for code readability. just for sinkbin-creation functions */
2238 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2240 x_bin[x_id].id = x_id;\
2241 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2242 if (!x_bin[x_id].gst) {\
2243 LOGE("failed to create %s \n", x_factory);\
2246 if (x_player->ini.set_dump_element_flag)\
2247 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2250 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2254 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
2259 MMPLAYER_RETURN_IF_FAIL(player);
2261 if (player->audio_stream_buff_list) {
2262 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2263 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2266 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2267 __mmplayer_audio_stream_send_data(player, tmp);
2270 g_free(tmp->pcm_data);
2274 g_list_free(player->audio_stream_buff_list);
2275 player->audio_stream_buff_list = NULL;
2282 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
2284 MMPlayerAudioStreamDataType audio_stream = { 0, };
2287 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2289 audio_stream.bitrate = a_buffer->bitrate;
2290 audio_stream.channel = a_buffer->channel;
2291 audio_stream.depth = a_buffer->depth;
2292 audio_stream.is_little_endian = a_buffer->is_little_endian;
2293 audio_stream.channel_mask = a_buffer->channel_mask;
2294 audio_stream.data_size = a_buffer->data_size;
2295 audio_stream.data = a_buffer->pcm_data;
2297 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
2298 player->audio_stream_render_cb(&audio_stream, player->audio_stream_cb_user_param);
2304 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
2306 mm_player_t* player = (mm_player_t*) data;
2311 gint endianness = 0;
2312 guint64 channel_mask = 0;
2313 void *a_data = NULL;
2315 mm_player_audio_stream_buff_t *a_buffer = NULL;
2316 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2320 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2322 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2323 a_data = mapinfo.data;
2324 a_size = mapinfo.size;
2326 GstCaps *caps = gst_pad_get_current_caps(pad);
2327 GstStructure *structure = gst_caps_get_structure(caps, 0);
2329 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2330 gst_structure_get_int(structure, "rate", &rate);
2331 gst_structure_get_int(structure, "channels", &channel);
2332 gst_structure_get_int(structure, "depth", &depth);
2333 gst_structure_get_int(structure, "endianness", &endianness);
2334 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2335 gst_caps_unref(GST_CAPS(caps));
2337 /* In case of the sync is false, use buffer list. *
2338 * The num of buffer list depends on the num of audio channels */
2339 if (player->audio_stream_buff_list) {
2340 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2341 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2343 if (channel_mask == tmp->channel_mask) {
2344 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2345 if (tmp->data_size + a_size < tmp->buff_size) {
2346 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2347 tmp->data_size += a_size;
2349 /* send data to client */
2350 __mmplayer_audio_stream_send_data(player, tmp);
2352 if (a_size > tmp->buff_size) {
2353 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2354 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2355 if (tmp->pcm_data == NULL) {
2356 LOGE("failed to realloc data.");
2359 tmp->buff_size = a_size;
2361 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2362 memcpy(tmp->pcm_data, a_data, a_size);
2363 tmp->data_size = a_size;
2368 LOGE("data is empty in list.");
2374 /* create new audio stream data */
2375 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
2376 if (a_buffer == NULL) {
2377 LOGE("failed to alloc data.");
2380 a_buffer->bitrate = rate;
2381 a_buffer->channel = channel;
2382 a_buffer->depth = depth;
2383 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
2384 a_buffer->channel_mask = channel_mask;
2385 a_buffer->data_size = a_size;
2387 if (!player->audio_stream_sink_sync) {
2388 /* If sync is FALSE, use buffer list to reduce the IPC. */
2389 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2390 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
2391 if (a_buffer->pcm_data == NULL) {
2392 LOGE("failed to alloc data.");
2396 memcpy(a_buffer->pcm_data, a_data, a_size);
2397 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2398 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2400 /* If sync is TRUE, send data directly. */
2401 a_buffer->pcm_data = a_data;
2402 __mmplayer_audio_stream_send_data(player, a_buffer);
2407 gst_buffer_unmap(buffer, &mapinfo);
2412 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2414 mm_player_t* player = (mm_player_t*)data;
2415 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
2416 GstPad* sinkpad = NULL;
2417 GstElement *queue = NULL, *sink = NULL;
2420 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2422 queue = gst_element_factory_make("queue", NULL);
2423 if (queue == NULL) {
2424 LOGD("fail make queue\n");
2428 sink = gst_element_factory_make("fakesink", NULL);
2430 LOGD("fail make fakesink\n");
2434 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2436 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2437 LOGW("failed to link queue & sink\n");
2441 sinkpad = gst_element_get_static_pad(queue, "sink");
2443 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2444 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
2448 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
2450 gst_object_unref(sinkpad);
2451 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
2452 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2454 gst_element_set_state(sink, GST_STATE_PAUSED);
2455 gst_element_set_state(queue, GST_STATE_PAUSED);
2457 __mmplayer_add_signal_connection(player,
2459 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2461 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2468 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
2470 gst_object_unref(GST_OBJECT(queue));
2474 gst_object_unref(GST_OBJECT(sink));
2478 gst_object_unref(GST_OBJECT(sinkpad));
2485 void __mmplayer_gst_set_pulsesink_property(mm_player_t* player, MMHandleType attrs)
2487 #define MAX_PROPS_LEN 128
2488 gint latency_mode = 0;
2489 gchar *stream_type = NULL;
2490 gchar *latency = NULL;
2492 gchar stream_props[MAX_PROPS_LEN] = {0,};
2493 GstStructure *props = NULL;
2496 * It should be set after player creation through attribute.
2497 * But, it can not be changed during playing.
2500 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2502 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
2503 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
2506 LOGE("stream_type is null.");
2508 if (player->sound.focus_id)
2509 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
2510 stream_type, stream_id, player->sound.focus_id);
2512 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
2513 stream_type, stream_id);
2514 props = gst_structure_from_string(stream_props, NULL);
2515 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2516 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].",
2517 stream_type, stream_id, player->sound.focus_id, stream_props);
2518 gst_structure_free(props);
2521 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2523 switch (latency_mode) {
2524 case AUDIO_LATENCY_MODE_LOW:
2525 latency = g_strndup("low", 3);
2527 case AUDIO_LATENCY_MODE_MID:
2528 latency = g_strndup("mid", 3);
2530 case AUDIO_LATENCY_MODE_HIGH:
2531 latency = g_strndup("high", 4);
2535 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2539 LOGD("audiosink property - latency=%s", latency);
2546 void __mmplayer_gst_set_openalsink_property(mm_player_t* player)
2548 MMPlayerGstElement *audiobin = NULL;
2551 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2553 audiobin = player->pipeline->audiobin;
2555 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2556 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2557 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2559 if (player->video360_yaw_radians <= M_PI &&
2560 player->video360_yaw_radians >= -M_PI &&
2561 player->video360_pitch_radians <= M_PI_2 &&
2562 player->video360_pitch_radians >= -M_PI_2) {
2563 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2564 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
2565 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
2566 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2567 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2568 "source-orientation-y", player->video360_metadata.init_view_heading,
2569 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2576 __mmplayer_gst_fill_audio_bucket(mm_player_t *player, GList **bucket)
2578 MMPlayerGstElement *audiobin = NULL;
2579 MMHandleType attrs = 0;
2580 GList *element_bucket = NULL;
2581 GstCaps *acaps = NULL;
2582 GstPad *sink_pad = NULL;
2585 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2586 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2588 audiobin = player->pipeline->audiobin;
2589 attrs = MMPLAYER_GET_ATTRS(player);
2592 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2594 /* replaygain volume */
2595 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2596 if (player->sound.rg_enable)
2597 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2599 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2602 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2604 if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2605 gchar *dst_format = NULL;
2607 int dst_samplerate = 0;
2608 int dst_channels = 0;
2609 GstCaps *caps = NULL;
2610 char *caps_str = NULL;
2612 /* get conf. values */
2613 mm_attrs_multiple_get(player->attrs, NULL,
2614 "pcm_audioformat", &dst_format, &dst_len,
2615 "pcm_extraction_samplerate", &dst_samplerate,
2616 "pcm_extraction_channels", &dst_channels,
2619 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2622 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2623 caps = gst_caps_new_simple("audio/x-raw",
2624 "format", G_TYPE_STRING, dst_format,
2625 "rate", G_TYPE_INT, dst_samplerate,
2626 "channels", G_TYPE_INT, dst_channels,
2629 caps_str = gst_caps_to_string(caps);
2630 LOGD("new caps : %s", caps_str);
2632 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2635 gst_caps_unref(caps);
2636 MMPLAYER_FREEIF(caps_str);
2638 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2640 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2642 /* raw pad handling signal, audiosink will be added after getting signal */
2643 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2644 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2648 /* normal playback */
2651 /* for logical volume control */
2652 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2653 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2655 if (player->sound.mute) {
2656 LOGD("mute enabled");
2657 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2660 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2662 /* audio effect element. if audio effect is enabled */
2663 if ((strcmp(player->ini.audioeffect_element, ""))
2665 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2666 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2668 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2670 if ((!player->bypass_audio_effect)
2671 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2672 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2673 if (!_mmplayer_audio_effect_custom_apply(player))
2674 LOGI("apply audio effect(custom) setting success");
2678 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2679 && (player->set_mode.rich_audio))
2680 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2683 /* create audio sink */
2684 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2685 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2686 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2688 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2689 if (player->is_360_feature_enabled &&
2690 player->is_content_spherical &&
2692 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2693 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2694 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2696 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2698 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2700 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2701 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2702 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2703 gst_caps_unref(acaps);
2705 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2707 player->is_openal_plugin_used = TRUE;
2709 if (player->is_360_feature_enabled && player->is_content_spherical)
2710 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2711 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2714 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2715 (player->videodec_linked && player->ini.use_system_clock)) {
2716 LOGD("system clock will be used.");
2717 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2720 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2721 __mmplayer_gst_set_pulsesink_property(player, attrs);
2722 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2723 __mmplayer_gst_set_openalsink_property(player);
2726 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2727 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2729 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2730 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2731 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2732 gst_object_unref(GST_OBJECT(sink_pad));
2734 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2737 *bucket = element_bucket;
2740 return MM_ERROR_NONE;
2743 g_list_free(element_bucket);
2747 return MM_ERROR_PLAYER_INTERNAL;
2751 __mmplayer_gst_create_audio_sink_bin(mm_player_t* player)
2753 MMPlayerGstElement *first_element = NULL;
2754 MMPlayerGstElement *audiobin = NULL;
2756 GstPad *ghostpad = NULL;
2757 GList *element_bucket = NULL;
2761 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2764 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2766 LOGE("failed to allocate memory for audiobin");
2767 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2771 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2772 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2773 if (!audiobin[MMPLAYER_A_BIN].gst) {
2774 LOGE("failed to create audiobin");
2779 player->pipeline->audiobin = audiobin;
2781 /* create audio filters and audiosink */
2782 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2785 /* adding created elements to bin */
2786 LOGD("adding created elements to bin");
2787 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2790 /* linking elements in the bucket by added order. */
2791 LOGD("Linking elements in the bucket by added order.");
2792 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2795 /* get first element's sinkpad for creating ghostpad */
2796 first_element = (MMPlayerGstElement *)element_bucket->data;
2797 if (!first_element) {
2798 LOGE("failed to get first elem");
2802 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2804 LOGE("failed to get pad from first element of audiobin");
2808 ghostpad = gst_ghost_pad_new("sink", pad);
2810 LOGE("failed to create ghostpad");
2814 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2815 LOGE("failed to add ghostpad to audiobin");
2819 gst_object_unref(pad);
2821 g_list_free(element_bucket);
2824 return MM_ERROR_NONE;
2827 LOGD("ERROR : releasing audiobin");
2830 gst_object_unref(GST_OBJECT(pad));
2833 gst_object_unref(GST_OBJECT(ghostpad));
2836 g_list_free(element_bucket);
2838 /* release element which are not added to bin */
2839 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2840 /* NOTE : skip bin */
2841 if (audiobin[i].gst) {
2842 GstObject* parent = NULL;
2843 parent = gst_element_get_parent(audiobin[i].gst);
2846 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2847 audiobin[i].gst = NULL;
2849 gst_object_unref(GST_OBJECT(parent));
2853 /* release audiobin with it's childs */
2854 if (audiobin[MMPLAYER_A_BIN].gst)
2855 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2857 MMPLAYER_FREEIF(audiobin);
2859 player->pipeline->audiobin = NULL;
2861 return MM_ERROR_PLAYER_INTERNAL;
2864 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
2866 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2869 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
2871 int ret = MM_ERROR_NONE;
2873 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2874 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2876 MMPLAYER_VIDEO_BO_LOCK(player);
2878 if (player->video_bo_list) {
2879 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2880 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
2881 if (tmp && tmp->bo == bo) {
2883 LOGD("release bo %p", bo);
2884 tbm_bo_unref(tmp->bo);
2885 MMPLAYER_VIDEO_BO_UNLOCK(player);
2886 MMPLAYER_VIDEO_BO_SIGNAL(player);
2891 /* hw codec is running or the list was reset for DRC. */
2892 LOGW("there is no bo list.");
2894 MMPLAYER_VIDEO_BO_UNLOCK(player);
2896 LOGW("failed to find bo %p", bo);
2901 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
2906 MMPLAYER_RETURN_IF_FAIL(player);
2908 MMPLAYER_VIDEO_BO_LOCK(player);
2909 if (player->video_bo_list) {
2910 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2911 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2912 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
2915 tbm_bo_unref(tmp->bo);
2919 g_list_free(player->video_bo_list);
2920 player->video_bo_list = NULL;
2922 player->video_bo_size = 0;
2923 MMPLAYER_VIDEO_BO_UNLOCK(player);
2930 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
2933 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2934 gboolean ret = TRUE;
2936 /* check DRC, if it is, destroy the prev bo list to create again */
2937 if (player->video_bo_size != size) {
2938 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
2939 __mmplayer_video_stream_destroy_bo_list(player);
2940 player->video_bo_size = size;
2943 MMPLAYER_VIDEO_BO_LOCK(player);
2945 if ((!player->video_bo_list) ||
2946 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
2948 /* create bo list */
2950 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
2952 if (player->video_bo_list) {
2953 /* if bo list did not created all, try it again. */
2954 idx = g_list_length(player->video_bo_list);
2955 LOGD("bo list exist(len: %d)", idx);
2958 for (; idx < player->ini.num_of_video_bo; idx++) {
2959 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
2961 LOGE("Fail to alloc bo_info.");
2964 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
2966 LOGE("Fail to tbm_bo_alloc.");
2970 bo_info->used = FALSE;
2971 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
2974 /* update video num buffers */
2975 player->video_num_buffers = idx;
2976 if (idx == player->ini.num_of_video_bo)
2977 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
2980 MMPLAYER_VIDEO_BO_UNLOCK(player);
2984 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
2988 /* get bo from list*/
2989 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2990 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
2991 if (tmp && (tmp->used == FALSE)) {
2992 LOGD("found bo %p to use", tmp->bo);
2994 MMPLAYER_VIDEO_BO_UNLOCK(player);
2995 return tbm_bo_ref(tmp->bo);
2999 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3000 MMPLAYER_VIDEO_BO_UNLOCK(player);
3004 if (player->ini.video_bo_timeout <= 0) {
3005 MMPLAYER_VIDEO_BO_WAIT(player);
3007 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
3008 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3015 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3017 mm_player_t* player = (mm_player_t*)data;
3019 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3021 /* send prerolled pkt */
3022 player->video_stream_prerolled = FALSE;
3024 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3026 /* not to send prerolled pkt again */
3027 player->video_stream_prerolled = TRUE;
3031 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3033 mm_player_t* player = (mm_player_t*)data;
3034 MMPlayerVideoStreamDataType *stream = NULL;
3035 GstMemory *mem = NULL;
3038 MMPLAYER_RETURN_IF_FAIL(player);
3039 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3041 if (player->video_stream_prerolled) {
3042 player->video_stream_prerolled = FALSE;
3043 LOGD("skip the prerolled pkt not to send it again");
3047 /* clear stream data structure */
3048 stream = __mmplayer_create_stream_from_pad(pad);
3050 LOGE("failed to alloc stream");
3054 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3056 /* set size and timestamp */
3057 mem = gst_buffer_peek_memory(buffer, 0);
3058 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3059 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3061 /* check zero-copy */
3062 if (player->set_mode.video_zc &&
3063 player->set_mode.media_packet_video_stream &&
3064 gst_is_tizen_memory(mem)) {
3065 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3066 stream->internal_buffer = gst_buffer_ref(buffer);
3067 } else { /* sw codec */
3068 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3071 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3075 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3076 LOGE("failed to send video stream data.");
3083 LOGE("release video stream resource.");
3084 if (gst_is_tizen_memory(mem)) {
3086 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3088 tbm_bo_unref(stream->bo[i]);
3091 /* unref gst buffer */
3092 if (stream->internal_buffer)
3093 gst_buffer_unref(stream->internal_buffer);
3096 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3103 __mmplayer_gst_set_video360_property(mm_player_t *player)
3105 MMPlayerGstElement *videobin = NULL;
3108 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3110 videobin = player->pipeline->videobin;
3112 /* Set spatial media metadata and/or user settings to the element.
3114 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3115 "projection-type", player->video360_metadata.projection_type, NULL);
3117 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3118 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3120 if (player->video360_metadata.full_pano_width_pixels &&
3121 player->video360_metadata.full_pano_height_pixels &&
3122 player->video360_metadata.cropped_area_image_width &&
3123 player->video360_metadata.cropped_area_image_height) {
3124 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3125 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3126 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3127 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3128 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3129 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3130 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3134 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3135 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3136 "horizontal-fov", player->video360_horizontal_fov,
3137 "vertical-fov", player->video360_vertical_fov, NULL);
3140 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3141 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3142 "zoom", 1.0f / player->video360_zoom, NULL);
3145 if (player->video360_yaw_radians <= M_PI &&
3146 player->video360_yaw_radians >= -M_PI &&
3147 player->video360_pitch_radians <= M_PI_2 &&
3148 player->video360_pitch_radians >= -M_PI_2) {
3149 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3150 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
3151 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
3152 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3153 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3154 "pose-yaw", player->video360_metadata.init_view_heading,
3155 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3158 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3159 "passthrough", !player->is_video360_enabled, NULL);
3166 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3168 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3169 GList *element_bucket = NULL;
3172 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3174 /* create video360 filter */
3175 if (player->is_360_feature_enabled && player->is_content_spherical) {
3176 LOGD("create video360 element");
3177 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3178 __mmplayer_gst_set_video360_property(player);
3182 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3183 LOGD("skip creating the videoconv and rotator");
3184 return MM_ERROR_NONE;
3187 /* in case of sw codec & overlay surface type, except 360 playback.
3188 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3189 LOGD("create video converter: %s", video_csc);
3190 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3192 /* set video rotator */
3193 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
3196 *bucket = element_bucket;
3198 return MM_ERROR_NONE;
3200 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3201 g_list_free(element_bucket);
3205 return MM_ERROR_PLAYER_INTERNAL;
3209 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3211 gchar *factory_name = NULL;
3213 switch (surface_type) {
3214 case MM_DISPLAY_SURFACE_OVERLAY:
3215 if (strlen(player->ini.videosink_element_overlay) > 0)
3216 factory_name = player->ini.videosink_element_overlay;
3218 case MM_DISPLAY_SURFACE_REMOTE:
3219 case MM_DISPLAY_SURFACE_NULL:
3220 if (strlen(player->ini.videosink_element_fake) > 0)
3221 factory_name = player->ini.videosink_element_fake;
3224 LOGE("unidentified surface type");
3228 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3229 return factory_name;
3233 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3235 gchar *factory_name = NULL;
3236 MMPlayerGstElement *videobin = NULL;
3241 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3243 videobin = player->pipeline->videobin;
3244 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3246 attrs = MMPLAYER_GET_ATTRS(player);
3248 LOGE("cannot get content attribute");
3249 return MM_ERROR_PLAYER_INTERNAL;
3252 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3253 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3254 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3256 /* support shard memory with S/W codec on HawkP */
3257 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3258 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3259 "use-tbm", use_tbm, NULL);
3263 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3264 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3267 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3269 LOGD("disable last-sample");
3270 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3273 if (player->set_mode.media_packet_video_stream) {
3275 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3276 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3277 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3279 __mmplayer_add_signal_connection(player,
3280 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3281 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3283 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3286 __mmplayer_add_signal_connection(player,
3287 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3288 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3290 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3294 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3295 return MM_ERROR_PLAYER_INTERNAL;
3297 if (videobin[MMPLAYER_V_SINK].gst) {
3298 GstPad *sink_pad = NULL;
3299 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3301 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3302 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3303 gst_object_unref(GST_OBJECT(sink_pad));
3305 LOGE("failed to get sink pad from videosink");
3309 return MM_ERROR_NONE;
3314 * - video overlay surface(arm/x86) : tizenwlsink
3317 __mmplayer_gst_create_video_sink_bin(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
3320 GList *element_bucket = NULL;
3321 MMPlayerGstElement *first_element = NULL;
3322 MMPlayerGstElement *videobin = NULL;
3323 gchar *videosink_factory_name = NULL;
3326 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3329 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3331 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3333 player->pipeline->videobin = videobin;
3336 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3337 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3338 if (!videobin[MMPLAYER_V_BIN].gst) {
3339 LOGE("failed to create videobin");
3343 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3346 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3347 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3349 /* additional setting for sink plug-in */
3350 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3351 LOGE("failed to set video property");
3355 /* store it as it's sink element */
3356 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3358 /* adding created elements to bin */
3359 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3360 LOGE("failed to add elements");
3364 /* Linking elements in the bucket by added order */
3365 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3366 LOGE("failed to link elements");
3370 /* get first element's sinkpad for creating ghostpad */
3371 first_element = (MMPlayerGstElement *)element_bucket->data;
3372 if (!first_element) {
3373 LOGE("failed to get first element from bucket");
3377 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3379 LOGE("failed to get pad from first element");
3383 /* create ghostpad */
3384 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3385 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3386 LOGE("failed to add ghostpad to videobin");
3389 gst_object_unref(pad);
3391 /* done. free allocated variables */
3392 g_list_free(element_bucket);
3396 return MM_ERROR_NONE;
3399 LOGE("ERROR : releasing videobin");
3400 g_list_free(element_bucket);
3403 gst_object_unref(GST_OBJECT(pad));
3405 /* release videobin with it's childs */
3406 if (videobin[MMPLAYER_V_BIN].gst)
3407 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3409 MMPLAYER_FREEIF(videobin);
3410 player->pipeline->videobin = NULL;
3412 return MM_ERROR_PLAYER_INTERNAL;
3415 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
3417 GList *element_bucket = NULL;
3418 MMPlayerGstElement *textbin = player->pipeline->textbin;
3420 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3421 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3422 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3423 "signal-handoffs", FALSE,
3426 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3427 __mmplayer_add_signal_connection(player,
3428 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3429 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3431 G_CALLBACK(__mmplayer_update_subtitle),
3434 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3435 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3437 if (!player->play_subtitle) {
3438 LOGD("add textbin sink as sink element of whole pipeline.\n");
3439 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3442 /* adding created elements to bin */
3443 LOGD("adding created elements to bin\n");
3444 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3445 LOGE("failed to add elements\n");
3449 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3450 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3451 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3453 /* linking elements in the bucket by added order. */
3454 LOGD("Linking elements in the bucket by added order.\n");
3455 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3456 LOGE("failed to link elements\n");
3460 /* done. free allocated variables */
3461 g_list_free(element_bucket);
3463 if (textbin[MMPLAYER_T_QUEUE].gst) {
3465 GstPad *ghostpad = NULL;
3467 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3469 LOGE("failed to get sink pad of text queue");
3473 ghostpad = gst_ghost_pad_new("text_sink", pad);
3474 gst_object_unref(pad);
3477 LOGE("failed to create ghostpad of textbin\n");
3481 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3482 LOGE("failed to add ghostpad to textbin\n");
3483 gst_object_unref(ghostpad);
3488 return MM_ERROR_NONE;
3491 g_list_free(element_bucket);
3493 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3494 LOGE("remove textbin sink from sink list");
3495 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3498 /* release element at __mmplayer_gst_create_text_sink_bin */
3499 return MM_ERROR_PLAYER_INTERNAL;
3502 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
3504 MMPlayerGstElement *textbin = NULL;
3505 GList *element_bucket = NULL;
3506 int surface_type = 0;
3511 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3514 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3516 LOGE("failed to allocate memory for textbin\n");
3517 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3521 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3522 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3523 if (!textbin[MMPLAYER_T_BIN].gst) {
3524 LOGE("failed to create textbin\n");
3529 player->pipeline->textbin = textbin;
3532 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3533 LOGD("surface type for subtitle : %d", surface_type);
3534 switch (surface_type) {
3535 case MM_DISPLAY_SURFACE_OVERLAY:
3536 case MM_DISPLAY_SURFACE_NULL:
3537 case MM_DISPLAY_SURFACE_REMOTE:
3538 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3539 LOGE("failed to make plain text elements\n");
3550 return MM_ERROR_NONE;
3554 LOGD("ERROR : releasing textbin\n");
3556 g_list_free(element_bucket);
3558 /* release signal */
3559 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3561 /* release element which are not added to bin */
3562 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3563 /* NOTE : skip bin */
3564 if (textbin[i].gst) {
3565 GstObject* parent = NULL;
3566 parent = gst_element_get_parent(textbin[i].gst);
3569 gst_object_unref(GST_OBJECT(textbin[i].gst));
3570 textbin[i].gst = NULL;
3572 gst_object_unref(GST_OBJECT(parent));
3577 /* release textbin with it's childs */
3578 if (textbin[MMPLAYER_T_BIN].gst)
3579 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3581 MMPLAYER_FREEIF(player->pipeline->textbin);
3582 player->pipeline->textbin = NULL;
3585 return MM_ERROR_PLAYER_INTERNAL;
3590 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
3592 MMPlayerGstElement* mainbin = NULL;
3593 MMPlayerGstElement* textbin = NULL;
3594 MMHandleType attrs = 0;
3595 GstElement *subsrc = NULL;
3596 GstElement *subparse = NULL;
3597 gchar *subtitle_uri = NULL;
3598 const gchar *charset = NULL;
3604 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3606 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3608 mainbin = player->pipeline->mainbin;
3610 attrs = MMPLAYER_GET_ATTRS(player);
3612 LOGE("cannot get content attribute\n");
3613 return MM_ERROR_PLAYER_INTERNAL;
3616 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3617 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3618 LOGE("subtitle uri is not proper filepath.\n");
3619 return MM_ERROR_PLAYER_INVALID_URI;
3622 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3623 LOGE("failed to get storage info of subtitle path");
3624 return MM_ERROR_PLAYER_INVALID_URI;
3627 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
3629 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3630 player->subtitle_language_list = NULL;
3631 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3633 /* create the subtitle source */
3634 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3636 LOGE("failed to create filesrc element\n");
3639 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3641 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3642 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3644 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3645 LOGW("failed to add queue\n");
3646 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3647 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3648 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3653 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3655 LOGE("failed to create subparse element\n");
3659 charset = util_get_charset(subtitle_uri);
3661 LOGD("detected charset is %s\n", charset);
3662 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3665 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3666 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3668 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3669 LOGW("failed to add subparse\n");
3670 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3671 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3672 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3676 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3677 LOGW("failed to link subsrc and subparse\n");
3681 player->play_subtitle = TRUE;
3682 player->adjust_subtitle_pos = 0;
3684 LOGD("play subtitle using subtitle file\n");
3686 if (player->pipeline->textbin == NULL) {
3687 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3688 LOGE("failed to create text sink bin. continuing without text\n");
3692 textbin = player->pipeline->textbin;
3694 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3695 LOGW("failed to add textbin\n");
3697 /* release signal */
3698 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3700 /* release textbin with it's childs */
3701 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3702 MMPLAYER_FREEIF(player->pipeline->textbin);
3703 player->pipeline->textbin = textbin = NULL;
3707 LOGD("link text input selector and textbin ghost pad");
3709 player->textsink_linked = 1;
3710 player->external_text_idx = 0;
3711 LOGI("textsink is linked");
3713 textbin = player->pipeline->textbin;
3714 LOGD("text bin has been created. reuse it.");
3715 player->external_text_idx = 1;
3718 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3719 LOGW("failed to link subparse and textbin\n");
3723 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3725 LOGE("failed to get sink pad from textsink to probe data");
3729 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3730 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3732 gst_object_unref(pad);
3735 /* create dot. for debugging */
3736 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3739 return MM_ERROR_NONE;
3742 /* release text pipeline resource */
3743 player->textsink_linked = 0;
3745 /* release signal */
3746 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3748 if (player->pipeline->textbin) {
3749 LOGE("remove textbin");
3751 /* release textbin with it's childs */
3752 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3753 MMPLAYER_FREEIF(player->pipeline->textbin);
3754 player->pipeline->textbin = NULL;
3758 /* release subtitle elem */
3759 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3760 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3762 return MM_ERROR_PLAYER_INTERNAL;
3766 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3768 mm_player_t* player = (mm_player_t*) data;
3769 MMMessageParamType msg = {0, };
3770 GstClockTime duration = 0;
3771 gpointer text = NULL;
3772 guint text_size = 0;
3773 gboolean ret = TRUE;
3774 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3778 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3779 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3781 if (player->is_subtitle_force_drop) {
3782 LOGW("subtitle is dropped forcedly.");
3786 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3787 text = mapinfo.data;
3788 text_size = mapinfo.size;
3789 duration = GST_BUFFER_DURATION(buffer);
3791 if (player->set_mode.subtitle_off) {
3792 LOGD("subtitle is OFF.\n");
3796 if (!text || (text_size == 0)) {
3797 LOGD("There is no subtitle to be displayed.\n");
3801 msg.data = (void *) text;
3802 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3804 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
3806 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3807 gst_buffer_unmap(buffer, &mapinfo);
3814 static GstPadProbeReturn
3815 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3817 mm_player_t *player = (mm_player_t *) u_data;
3818 GstClockTime cur_timestamp = 0;
3819 gint64 adjusted_timestamp = 0;
3820 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3822 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3824 if (player->set_mode.subtitle_off) {
3825 LOGD("subtitle is OFF.\n");
3829 if (player->adjust_subtitle_pos == 0) {
3830 LOGD("nothing to do");
3834 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3835 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3837 if (adjusted_timestamp < 0) {
3838 LOGD("adjusted_timestamp under zero");
3843 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3844 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3845 GST_TIME_ARGS(cur_timestamp),
3846 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3848 return GST_PAD_PROBE_OK;
3850 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
3854 /* check player and subtitlebin are created */
3855 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3856 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3858 if (position == 0) {
3859 LOGD("nothing to do\n");
3861 return MM_ERROR_NONE;
3865 case MM_PLAYER_POS_FORMAT_TIME:
3867 /* check current postion */
3868 player->adjust_subtitle_pos = position;
3870 LOGD("save adjust_subtitle_pos in player") ;
3876 LOGW("invalid format.\n");
3878 return MM_ERROR_INVALID_ARGUMENT;
3884 return MM_ERROR_NONE;
3888 * This function is to create audio or video pipeline for playing.
3890 * @param player [in] handle of player
3892 * @return This function returns zero on success.
3897 __mmplayer_gst_create_pipeline(mm_player_t* player)
3899 int ret = MM_ERROR_NONE;
3900 MMPlayerGstElement *mainbin = NULL;
3901 MMHandleType attrs = 0;
3904 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3906 /* get profile attribute */
3907 attrs = MMPLAYER_GET_ATTRS(player);
3909 LOGE("failed to get content attribute");
3913 /* create pipeline handles */
3914 if (player->pipeline) {
3915 LOGE("pipeline should be released before create new one");
3919 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
3920 if (player->pipeline == NULL)
3923 /* create mainbin */
3924 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
3925 if (mainbin == NULL)
3928 /* create pipeline */
3929 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3930 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3931 if (!mainbin[MMPLAYER_M_PIPE].gst) {
3932 LOGE("failed to create pipeline");
3937 player->pipeline->mainbin = mainbin;
3939 /* create the source and decoder elements */
3940 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3941 ret = __mmplayer_gst_build_es_pipeline(player);
3943 ret = __mmplayer_gst_build_pipeline(player);
3945 if (ret != MM_ERROR_NONE) {
3946 LOGE("failed to create some elements");
3950 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
3951 if (__mmplayer_check_subtitle(player)) {
3952 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE)
3953 LOGE("failed to create text pipeline");
3957 ret = __mmplayer_gst_add_bus_watch(player);
3958 if (ret != MM_ERROR_NONE) {
3959 LOGE("failed to add bus watch");
3964 return MM_ERROR_NONE;
3967 __mmplayer_gst_destroy_pipeline(player);
3968 return MM_ERROR_PLAYER_INTERNAL;
3972 __mmplayer_reset_gapless_state(mm_player_t* player)
3975 MMPLAYER_RETURN_IF_FAIL(player
3977 && player->pipeline->audiobin
3978 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
3980 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
3987 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
3990 int ret = MM_ERROR_NONE;
3994 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
3996 /* cleanup stuffs */
3997 MMPLAYER_FREEIF(player->type);
3998 player->no_more_pad = FALSE;
3999 player->num_dynamic_pad = 0;
4000 player->demux_pad_index = 0;
4002 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4003 player->subtitle_language_list = NULL;
4004 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4006 __mmplayer_reset_gapless_state(player);
4008 if (player->streamer) {
4009 __mm_player_streaming_deinitialize(player->streamer);
4010 __mm_player_streaming_destroy(player->streamer);
4011 player->streamer = NULL;
4014 /* cleanup unlinked mime type */
4015 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4016 MMPLAYER_FREEIF(player->unlinked_video_mime);
4017 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4019 /* cleanup running stuffs */
4020 __mmplayer_cancel_eos_timer(player);
4022 /* cleanup gst stuffs */
4023 if (player->pipeline) {
4024 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
4025 GstTagList* tag_list = player->pipeline->tag_list;
4027 /* first we need to disconnect all signal hander */
4028 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4031 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4032 MMPlayerGstElement* videobin = player->pipeline->videobin;
4033 MMPlayerGstElement* textbin = player->pipeline->textbin;
4034 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4035 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4036 gst_object_unref(bus);
4038 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4039 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4040 if (ret != MM_ERROR_NONE) {
4041 LOGE("fail to change state to NULL\n");
4042 return MM_ERROR_PLAYER_INTERNAL;
4045 LOGW("succeeded in changing state to NULL\n");
4047 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4050 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4051 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4053 /* free avsysaudiosink
4054 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4055 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4057 MMPLAYER_FREEIF(audiobin);
4058 MMPLAYER_FREEIF(videobin);
4059 MMPLAYER_FREEIF(textbin);
4060 MMPLAYER_FREEIF(mainbin);
4064 gst_tag_list_unref(tag_list);
4066 MMPLAYER_FREEIF(player->pipeline);
4068 MMPLAYER_FREEIF(player->album_art);
4070 if (player->v_stream_caps) {
4071 gst_caps_unref(player->v_stream_caps);
4072 player->v_stream_caps = NULL;
4074 if (player->a_stream_caps) {
4075 gst_caps_unref(player->a_stream_caps);
4076 player->a_stream_caps = NULL;
4079 if (player->s_stream_caps) {
4080 gst_caps_unref(player->s_stream_caps);
4081 player->s_stream_caps = NULL;
4083 __mmplayer_track_destroy(player);
4085 if (player->sink_elements)
4086 g_list_free(player->sink_elements);
4087 player->sink_elements = NULL;
4089 if (player->bufmgr) {
4090 tbm_bufmgr_deinit(player->bufmgr);
4091 player->bufmgr = NULL;
4094 LOGW("finished destroy pipeline\n");
4101 static int __mmplayer_gst_realize(mm_player_t* player)
4104 int ret = MM_ERROR_NONE;
4108 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4110 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4112 ret = __mmplayer_gst_create_pipeline(player);
4114 LOGE("failed to create pipeline\n");
4118 /* set pipeline state to READY */
4119 /* NOTE : state change to READY must be performed sync. */
4120 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4121 ret = __mmplayer_gst_set_state(player,
4122 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4124 if (ret != MM_ERROR_NONE) {
4125 /* return error if failed to set state */
4126 LOGE("failed to set READY state");
4130 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4132 /* create dot before error-return. for debugging */
4133 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4140 static int __mmplayer_gst_unrealize(mm_player_t* player)
4142 int ret = MM_ERROR_NONE;
4146 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4148 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4149 MMPLAYER_PRINT_STATE(player);
4151 /* release miscellaneous information */
4152 __mmplayer_release_misc(player);
4154 /* destroy pipeline */
4155 ret = __mmplayer_gst_destroy_pipeline(player);
4156 if (ret != MM_ERROR_NONE) {
4157 LOGE("failed to destory pipeline\n");
4161 /* release miscellaneous information.
4162 these info needs to be released after pipeline is destroyed. */
4163 __mmplayer_release_misc_post(player);
4165 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4173 __mmplayer_gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
4178 LOGW("set_message_callback is called with invalid player handle\n");
4179 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4182 player->msg_cb = callback;
4183 player->msg_cb_param = user_param;
4185 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
4189 return MM_ERROR_NONE;
4192 int __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
4194 int ret = MM_ERROR_NONE;
4199 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4200 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4201 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4203 memset(data, 0, sizeof(MMPlayerParseProfile));
4205 if (strstr(uri, "es_buff://")) {
4206 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4207 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4208 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4209 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4211 tmp = g_ascii_strdown(uri, strlen(uri));
4212 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4213 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4215 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4217 } else if (strstr(uri, "mms://")) {
4218 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4219 } else if ((path = strstr(uri, "mem://"))) {
4220 ret = __mmplayer_set_mem_uri(data, path, param);
4222 ret = __mmplayer_set_file_uri(data, uri);
4225 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4226 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4227 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4228 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4230 /* dump parse result */
4231 SECURE_LOGW("incoming uri : %s\n", uri);
4232 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
4233 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4241 __mmplayer_can_do_interrupt(mm_player_t *player)
4243 if (!player || !player->pipeline || !player->attrs) {
4244 LOGW("not initialized");
4248 if (player->audio_stream_render_cb) {
4249 LOGW("not support in pcm extraction mode");
4253 /* check if seeking */
4254 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4255 MMMessageParamType msg_param;
4256 memset(&msg_param, 0, sizeof(MMMessageParamType));
4257 msg_param.code = MM_ERROR_PLAYER_SEEK;
4258 player->seek_state = MMPLAYER_SEEK_NONE;
4259 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4263 /* check other thread */
4264 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4265 LOGW("locked already, cmd state : %d", player->cmd);
4267 /* check application command */
4268 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4269 LOGW("playing.. should wait cmd lock then, will be interrupted");
4271 /* lock will be released at mrp_resource_release_cb() */
4272 MMPLAYER_CMD_LOCK(player);
4275 LOGW("nothing to do");
4278 LOGW("can interrupt immediately");
4282 FAILED: /* with CMD UNLOCKED */
4285 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4290 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4293 mm_player_t *player = NULL;
4297 if (user_data == NULL) {
4298 LOGE("- user_data is null\n");
4301 player = (mm_player_t *)user_data;
4303 /* do something to release resource here.
4304 * player stop and interrupt forwarding */
4305 if (!__mmplayer_can_do_interrupt(player)) {
4306 LOGW("no need to interrupt, so leave");
4308 MMMessageParamType msg = {0, };
4311 player->interrupted_by_resource = TRUE;
4313 /* get last play position */
4314 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4315 LOGW("failed to get play position.");
4317 msg.union_type = MM_MSG_UNION_TIME;
4318 msg.time.elapsed = pos;
4319 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4321 LOGD("video resource conflict so, resource will be freed by unrealizing");
4322 if (_mmplayer_unrealize((MMHandleType)player))
4323 LOGW("failed to unrealize");
4325 /* lock is called in __mmplayer_can_do_interrupt() */
4326 MMPLAYER_CMD_UNLOCK(player);
4329 if (res == player->video_overlay_resource)
4330 player->video_overlay_resource = FALSE;
4332 player->video_decoder_resource = FALSE;
4340 __mmplayer_initialize_video_roi(mm_player_t *player)
4342 player->video_roi.scale_x = 0.0;
4343 player->video_roi.scale_y = 0.0;
4344 player->video_roi.scale_width = 1.0;
4345 player->video_roi.scale_height = 1.0;
4349 _mmplayer_create_player(MMHandleType handle)
4351 int ret = MM_ERROR_PLAYER_INTERNAL;
4352 bool enabled = false;
4354 mm_player_t* player = MM_PLAYER_CAST(handle);
4358 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4360 /* initialize player state */
4361 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4362 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4363 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4364 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4366 /* check current state */
4367 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4369 /* construct attributes */
4370 player->attrs = _mmplayer_construct_attribute(handle);
4372 if (!player->attrs) {
4373 LOGE("Failed to construct attributes\n");
4377 /* initialize gstreamer with configured parameter */
4378 if (!__mmplayer_init_gstreamer(player)) {
4379 LOGE("Initializing gstreamer failed\n");
4380 _mmplayer_deconstruct_attribute(handle);
4384 /* create lock. note that g_tread_init() has already called in gst_init() */
4385 g_mutex_init(&player->fsink_lock);
4387 /* create update tag lock */
4388 g_mutex_init(&player->update_tag_lock);
4390 /* create gapless play mutex */
4391 g_mutex_init(&player->gapless_play_thread_mutex);
4393 /* create gapless play cond */
4394 g_cond_init(&player->gapless_play_thread_cond);
4396 /* create gapless play thread */
4397 player->gapless_play_thread =
4398 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4399 if (!player->gapless_play_thread) {
4400 LOGE("failed to create gapless play thread");
4401 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4402 g_mutex_clear(&player->gapless_play_thread_mutex);
4403 g_cond_clear(&player->gapless_play_thread_cond);
4407 player->bus_msg_q = g_queue_new();
4408 if (!player->bus_msg_q) {
4409 LOGE("failed to create queue for bus_msg");
4410 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4414 ret = _mmplayer_initialize_video_capture(player);
4415 if (ret != MM_ERROR_NONE) {
4416 LOGE("failed to initialize video capture\n");
4420 /* check resource manager state */
4421 if (access(MM_RESOURCE_MANAGER_READY, F_OK) != 0) {
4422 LOGE("resource manager is not ready");
4423 ret = MM_ERROR_PLAYER_INTERNAL;
4427 /* initialize resource manager */
4428 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4429 __resource_release_cb, player, &player->resource_manager)
4430 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4431 LOGE("failed to initialize resource manager");
4432 ret = MM_ERROR_PLAYER_INTERNAL;
4436 /* create video bo lock and cond */
4437 g_mutex_init(&player->video_bo_mutex);
4438 g_cond_init(&player->video_bo_cond);
4440 /* create media stream callback mutex */
4441 g_mutex_init(&player->media_stream_cb_lock);
4443 /* create subtitle info lock and cond */
4444 g_mutex_init(&player->subtitle_info_mutex);
4445 g_cond_init(&player->subtitle_info_cond);
4447 player->streaming_type = STREAMING_SERVICE_NONE;
4449 /* give default value of audio effect setting */
4450 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4451 player->sound.rg_enable = false;
4452 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4454 player->play_subtitle = FALSE;
4455 player->has_closed_caption = FALSE;
4456 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4457 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4458 player->pending_resume = FALSE;
4459 if (player->ini.dump_element_keyword[0][0] == '\0')
4460 player->ini.set_dump_element_flag = FALSE;
4462 player->ini.set_dump_element_flag = TRUE;
4464 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4465 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4466 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4468 /* Set video360 settings to their defaults for just-created player.
4471 player->is_360_feature_enabled = FALSE;
4472 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4473 LOGI("spherical feature info: %d", enabled);
4475 player->is_360_feature_enabled = TRUE;
4477 LOGE("failed to get spherical feature info");
4480 player->is_content_spherical = FALSE;
4481 player->is_video360_enabled = TRUE;
4482 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4483 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4484 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4485 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4486 player->video360_zoom = 1.0f;
4487 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4488 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4490 __mmplayer_initialize_video_roi(player);
4492 /* set player state to null */
4493 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4494 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4498 return MM_ERROR_NONE;
4502 g_mutex_clear(&player->fsink_lock);
4504 /* free update tag lock */
4505 g_mutex_clear(&player->update_tag_lock);
4507 g_queue_free(player->bus_msg_q);
4509 /* free gapless play thread */
4510 if (player->gapless_play_thread) {
4511 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4512 player->gapless_play_thread_exit = TRUE;
4513 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4514 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4516 g_thread_join(player->gapless_play_thread);
4517 player->gapless_play_thread = NULL;
4519 g_mutex_clear(&player->gapless_play_thread_mutex);
4520 g_cond_clear(&player->gapless_play_thread_cond);
4523 /* release attributes */
4524 _mmplayer_deconstruct_attribute(handle);
4532 __mmplayer_init_gstreamer(mm_player_t* player)
4534 static gboolean initialized = FALSE;
4535 static const int max_argc = 50;
4537 gchar** argv = NULL;
4538 gchar** argv2 = NULL;
4544 LOGD("gstreamer already initialized.\n");
4549 argc = malloc(sizeof(int));
4550 argv = malloc(sizeof(gchar*) * max_argc);
4551 argv2 = malloc(sizeof(gchar*) * max_argc);
4553 if (!argc || !argv || !argv2)
4556 memset(argv, 0, sizeof(gchar*) * max_argc);
4557 memset(argv2, 0, sizeof(gchar*) * max_argc);
4561 argv[0] = g_strdup("mmplayer");
4564 for (i = 0; i < 5; i++) {
4565 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4566 if (strlen(player->ini.gst_param[i]) > 0) {
4567 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4572 /* we would not do fork for scanning plugins */
4573 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4576 /* check disable registry scan */
4577 if (player->ini.skip_rescan) {
4578 argv[*argc] = g_strdup("--gst-disable-registry-update");
4582 /* check disable segtrap */
4583 if (player->ini.disable_segtrap) {
4584 argv[*argc] = g_strdup("--gst-disable-segtrap");
4588 LOGD("initializing gstreamer with following parameter\n");
4589 LOGD("argc : %d\n", *argc);
4592 for (i = 0; i < arg_count; i++) {
4594 LOGD("argv[%d] : %s\n", i, argv2[i]);
4597 /* initializing gstreamer */
4598 if (!gst_init_check(argc, &argv, &err)) {
4599 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
4606 for (i = 0; i < arg_count; i++) {
4607 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
4608 MMPLAYER_FREEIF(argv2[i]);
4611 MMPLAYER_FREEIF(argv);
4612 MMPLAYER_FREEIF(argv2);
4613 MMPLAYER_FREEIF(argc);
4623 for (i = 0; i < arg_count; i++) {
4624 LOGD("free[%d] : %s\n", i, argv2[i]);
4625 MMPLAYER_FREEIF(argv2[i]);
4628 MMPLAYER_FREEIF(argv);
4629 MMPLAYER_FREEIF(argv2);
4630 MMPLAYER_FREEIF(argc);
4636 __mmplayer_check_async_state_transition(mm_player_t* player)
4638 GstState element_state = GST_STATE_VOID_PENDING;
4639 GstState element_pending_state = GST_STATE_VOID_PENDING;
4640 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4641 GstElement * element = NULL;
4642 gboolean async = FALSE;
4644 /* check player handle */
4645 MMPLAYER_RETURN_IF_FAIL(player &&
4647 player->pipeline->mainbin &&
4648 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4651 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4653 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4654 LOGD("don't need to check the pipeline state");
4658 MMPLAYER_PRINT_STATE(player);
4660 /* wait for state transition */
4661 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4662 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
4664 if (ret == GST_STATE_CHANGE_FAILURE) {
4665 LOGE(" [%s] state : %s pending : %s \n",
4666 GST_ELEMENT_NAME(element),
4667 gst_element_state_get_name(element_state),
4668 gst_element_state_get_name(element_pending_state));
4670 /* dump state of all element */
4671 __mmplayer_dump_pipeline_state(player);
4676 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
4681 _mmplayer_destroy(MMHandleType handle)
4683 mm_player_t* player = MM_PLAYER_CAST(handle);
4687 /* check player handle */
4688 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4690 /* destroy can called at anytime */
4691 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4693 /* check async state transition */
4694 __mmplayer_check_async_state_transition(player);
4696 /* release gapless play thread */
4697 if (player->gapless_play_thread) {
4698 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4699 player->gapless_play_thread_exit = TRUE;
4700 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4701 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4703 LOGD("waitting for gapless play thread exit\n");
4704 g_thread_join(player->gapless_play_thread);
4705 g_mutex_clear(&player->gapless_play_thread_mutex);
4706 g_cond_clear(&player->gapless_play_thread_cond);
4707 LOGD("gapless play thread released\n");
4710 _mmplayer_release_video_capture(player);
4712 /* de-initialize resource manager */
4713 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4714 player->resource_manager))
4715 LOGE("failed to deinitialize resource manager\n");
4717 /* release pipeline */
4718 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4719 LOGE("failed to destory pipeline\n");
4720 return MM_ERROR_PLAYER_INTERNAL;
4723 g_queue_free(player->bus_msg_q);
4725 /* release subtitle info lock and cond */
4726 g_mutex_clear(&player->subtitle_info_mutex);
4727 g_cond_clear(&player->subtitle_info_cond);
4729 __mmplayer_release_dump_list(player->dump_list);
4731 /* release miscellaneous information */
4732 __mmplayer_release_misc(player);
4734 /* release miscellaneous information.
4735 these info needs to be released after pipeline is destroyed. */
4736 __mmplayer_release_misc_post(player);
4738 /* release attributes */
4739 _mmplayer_deconstruct_attribute(handle);
4742 g_mutex_clear(&player->fsink_lock);
4745 g_mutex_clear(&player->update_tag_lock);
4747 /* release video bo lock and cond */
4748 g_mutex_clear(&player->video_bo_mutex);
4749 g_cond_clear(&player->video_bo_cond);
4751 /* release media stream callback lock */
4752 g_mutex_clear(&player->media_stream_cb_lock);
4756 return MM_ERROR_NONE;
4760 _mmplayer_realize(MMHandleType hplayer)
4762 mm_player_t* player = (mm_player_t*)hplayer;
4765 MMHandleType attrs = 0;
4766 int ret = MM_ERROR_NONE;
4770 /* check player handle */
4771 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4773 /* check current state */
4774 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4776 attrs = MMPLAYER_GET_ATTRS(player);
4778 LOGE("fail to get attributes.\n");
4779 return MM_ERROR_PLAYER_INTERNAL;
4781 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4782 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4784 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4785 ret = __mmplayer_parse_profile((const char*)uri, param, &player->profile);
4787 if (ret != MM_ERROR_NONE) {
4788 LOGE("failed to parse profile");
4793 if (uri && (strstr(uri, "es_buff://"))) {
4794 if (strstr(uri, "es_buff://push_mode"))
4795 player->es_player_push_mode = TRUE;
4797 player->es_player_push_mode = FALSE;
4800 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4801 LOGW("mms protocol is not supported format.\n");
4802 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4805 if (MMPLAYER_IS_STREAMING(player))
4806 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4808 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4810 player->smooth_streaming = FALSE;
4811 player->videodec_linked = 0;
4812 player->audiodec_linked = 0;
4813 player->textsink_linked = 0;
4814 player->is_external_subtitle_present = FALSE;
4815 player->is_external_subtitle_added_now = FALSE;
4816 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4817 player->video360_metadata.is_spherical = -1;
4818 player->is_openal_plugin_used = FALSE;
4819 player->demux_pad_index = 0;
4820 player->subtitle_language_list = NULL;
4821 player->is_subtitle_force_drop = FALSE;
4822 player->last_multiwin_status = FALSE;
4824 __mmplayer_track_initialize(player);
4825 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4827 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4828 player->streamer = __mm_player_streaming_create();
4829 __mm_player_streaming_initialize(player->streamer);
4832 /* realize pipeline */
4833 ret = __mmplayer_gst_realize(player);
4834 if (ret != MM_ERROR_NONE)
4835 LOGE("fail to realize the player.\n");
4837 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4845 _mmplayer_unrealize(MMHandleType hplayer)
4847 mm_player_t* player = (mm_player_t*)hplayer;
4848 int ret = MM_ERROR_NONE;
4852 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4854 MMPLAYER_CMD_UNLOCK(player);
4855 /* destroy the gst bus msg thread which is created during realize.
4856 this funct have to be called before getting cmd lock. */
4857 __mmplayer_bus_msg_thread_destroy(player);
4858 MMPLAYER_CMD_LOCK(player);
4860 /* check current state */
4861 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4863 /* check async state transition */
4864 __mmplayer_check_async_state_transition(player);
4866 /* unrealize pipeline */
4867 ret = __mmplayer_gst_unrealize(player);
4869 /* set asm stop if success */
4870 if (MM_ERROR_NONE == ret) {
4871 if (!player->interrupted_by_resource) {
4872 if (player->video_decoder_resource != NULL) {
4873 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4874 player->video_decoder_resource);
4875 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4876 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
4878 player->video_decoder_resource = NULL;
4881 if (player->video_overlay_resource != NULL) {
4882 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4883 player->video_overlay_resource);
4884 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4885 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
4887 player->video_overlay_resource = NULL;
4890 ret = mm_resource_manager_commit(player->resource_manager);
4891 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4892 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
4895 LOGE("failed and don't change asm state to stop");
4903 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
4905 mm_player_t* player = (mm_player_t*)hplayer;
4907 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4909 return __mmplayer_gst_set_message_callback(player, callback, user_param);
4913 _mmplayer_get_state(MMHandleType hplayer, int* state)
4915 mm_player_t *player = (mm_player_t*)hplayer;
4917 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
4919 *state = MMPLAYER_CURRENT_STATE(player);
4921 return MM_ERROR_NONE;
4926 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
4928 mm_player_t* player = (mm_player_t*) hplayer;
4929 GstElement* vol_element = NULL;
4934 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4936 LOGD("volume [L]=%f:[R]=%f\n",
4937 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
4939 /* invalid factor range or not */
4940 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
4941 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
4942 LOGE("Invalid factor!(valid factor:0~1.0)\n");
4943 return MM_ERROR_INVALID_ARGUMENT;
4947 /* not support to set other value into each channel */
4948 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
4949 return MM_ERROR_INVALID_ARGUMENT;
4951 /* Save volume to handle. Currently the first array element will be saved. */
4952 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
4954 /* check pipeline handle */
4955 if (!player->pipeline || !player->pipeline->audiobin) {
4956 LOGD("audiobin is not created yet\n");
4957 LOGD("but, current stored volume will be set when it's created.\n");
4959 /* NOTE : stored volume will be used in create_audiobin
4960 * returning MM_ERROR_NONE here makes application to able to
4961 * set volume at anytime.
4963 return MM_ERROR_NONE;
4966 /* setting volume to volume element */
4967 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
4970 LOGD("volume is set [%f]\n", player->sound.volume);
4971 g_object_set(vol_element, "volume", player->sound.volume, NULL);
4976 return MM_ERROR_NONE;
4981 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
4983 mm_player_t* player = (mm_player_t*) hplayer;
4988 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4989 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
4991 /* returning stored volume */
4992 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
4993 volume->level[i] = player->sound.volume;
4997 return MM_ERROR_NONE;
5001 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5003 mm_player_t* player = (mm_player_t*) hplayer;
5004 GstElement* vol_element = NULL;
5008 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5010 /* mute value shoud 0 or 1 */
5011 if (mute != 0 && mute != 1) {
5012 LOGE("bad mute value\n");
5014 /* FIXIT : definitly, we need _BAD_PARAM error code */
5015 return MM_ERROR_INVALID_ARGUMENT;
5018 player->sound.mute = mute;
5020 /* just hold mute value if pipeline is not ready */
5021 if (!player->pipeline || !player->pipeline->audiobin) {
5022 LOGD("pipeline is not ready. holding mute value\n");
5023 return MM_ERROR_NONE;
5026 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5028 /* NOTE : volume will only created when the bt is enabled */
5030 LOGD("mute : %d\n", mute);
5031 g_object_set(vol_element, "mute", mute, NULL);
5033 LOGD("volume elemnet is not created. using volume in audiosink\n");
5037 return MM_ERROR_NONE;
5041 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
5043 mm_player_t* player = (mm_player_t*) hplayer;
5047 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5048 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5050 /* just hold mute value if pipeline is not ready */
5051 if (!player->pipeline || !player->pipeline->audiobin) {
5052 LOGD("pipeline is not ready. returning stored value\n");
5053 *pmute = player->sound.mute;
5054 return MM_ERROR_NONE;
5057 *pmute = player->sound.mute;
5061 return MM_ERROR_NONE;
5065 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5067 mm_player_t* player = (mm_player_t*) hplayer;
5071 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5073 player->video_stream_changed_cb = callback;
5074 player->video_stream_changed_cb_user_param = user_param;
5075 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
5079 return MM_ERROR_NONE;
5083 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5085 mm_player_t* player = (mm_player_t*) hplayer;
5089 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5091 player->audio_stream_changed_cb = callback;
5092 player->audio_stream_changed_cb_user_param = user_param;
5093 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
5097 return MM_ERROR_NONE;
5101 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5103 mm_player_t *player = (mm_player_t*) hplayer;
5107 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5109 player->audio_stream_render_cb = callback;
5110 player->audio_stream_cb_user_param = user_param;
5111 player->audio_stream_sink_sync = sync;
5112 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5116 return MM_ERROR_NONE;
5120 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5122 mm_player_t* player = (mm_player_t*) hplayer;
5126 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5128 if (callback && !player->bufmgr)
5129 player->bufmgr = tbm_bufmgr_init(-1);
5131 player->set_mode.media_packet_video_stream = (callback) ? true : false;
5132 player->video_stream_cb = callback;
5133 player->video_stream_cb_user_param = user_param;
5135 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5139 return MM_ERROR_NONE;
5143 _mmplayer_start(MMHandleType hplayer)
5145 mm_player_t* player = (mm_player_t*) hplayer;
5146 gint ret = MM_ERROR_NONE;
5150 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5152 /* check current state */
5153 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5155 /* start pipeline */
5156 ret = __mmplayer_gst_start(player);
5157 if (ret != MM_ERROR_NONE)
5158 LOGE("failed to start player.\n");
5160 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5161 LOGD("force playing start even during buffering");
5162 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5170 /* NOTE: post "not supported codec message" to application
5171 * when one codec is not found during AUTOPLUGGING in MSL.
5172 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5173 * And, if any codec is not found, don't send message here.
5174 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5177 __mmplayer_handle_missed_plugin(mm_player_t* player)
5179 MMMessageParamType msg_param;
5180 memset(&msg_param, 0, sizeof(MMMessageParamType));
5181 gboolean post_msg_direct = FALSE;
5185 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5187 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
5188 player->not_supported_codec, player->can_support_codec);
5190 if (player->not_found_demuxer) {
5191 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5192 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5194 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5195 MMPLAYER_FREEIF(msg_param.data);
5197 return MM_ERROR_NONE;
5200 if (player->not_supported_codec) {
5201 if (player->can_support_codec) {
5202 // There is one codec to play
5203 post_msg_direct = TRUE;
5205 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5206 post_msg_direct = TRUE;
5209 if (post_msg_direct) {
5210 MMMessageParamType msg_param;
5211 memset(&msg_param, 0, sizeof(MMMessageParamType));
5213 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5214 LOGW("not found AUDIO codec, posting error code to application.\n");
5216 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5217 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5218 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5219 LOGW("not found VIDEO codec, posting error code to application.\n");
5221 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5222 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5225 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5227 MMPLAYER_FREEIF(msg_param.data);
5229 return MM_ERROR_NONE;
5231 // no any supported codec case
5232 LOGW("not found any codec, posting error code to application.\n");
5234 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5235 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5236 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5238 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5239 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5242 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5244 MMPLAYER_FREEIF(msg_param.data);
5250 return MM_ERROR_NONE;
5253 static void __mmplayer_check_pipeline(mm_player_t* player)
5255 GstState element_state = GST_STATE_VOID_PENDING;
5256 GstState element_pending_state = GST_STATE_VOID_PENDING;
5258 int ret = MM_ERROR_NONE;
5260 if (player->gapless.reconfigure) {
5261 LOGW("pipeline is under construction.\n");
5263 MMPLAYER_PLAYBACK_LOCK(player);
5264 MMPLAYER_PLAYBACK_UNLOCK(player);
5266 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5268 /* wait for state transition */
5269 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5271 if (ret == GST_STATE_CHANGE_FAILURE)
5272 LOGE("failed to change pipeline state within %d sec\n", timeout);
5276 /* NOTE : it should be able to call 'stop' anytime*/
5278 _mmplayer_stop(MMHandleType hplayer)
5280 mm_player_t* player = (mm_player_t*)hplayer;
5281 int ret = MM_ERROR_NONE;
5285 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5287 /* check current state */
5288 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5290 /* check pipline building state */
5291 __mmplayer_check_pipeline(player);
5292 __mmplayer_reset_gapless_state(player);
5294 /* NOTE : application should not wait for EOS after calling STOP */
5295 __mmplayer_cancel_eos_timer(player);
5298 player->seek_state = MMPLAYER_SEEK_NONE;
5301 ret = __mmplayer_gst_stop(player);
5303 if (ret != MM_ERROR_NONE)
5304 LOGE("failed to stop player.\n");
5312 _mmplayer_pause(MMHandleType hplayer)
5314 mm_player_t* player = (mm_player_t*)hplayer;
5315 gint64 pos_nsec = 0;
5316 gboolean async = FALSE;
5317 gint ret = MM_ERROR_NONE;
5321 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5323 /* check current state */
5324 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5326 /* check pipline building state */
5327 __mmplayer_check_pipeline(player);
5329 switch (MMPLAYER_CURRENT_STATE(player)) {
5330 case MM_PLAYER_STATE_READY:
5332 /* check prepare async or not.
5333 * In the case of streaming playback, it's recommned to avoid blocking wait.
5335 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5336 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5338 /* Changing back sync of rtspsrc to async */
5339 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5340 LOGD("async prepare working mode for rtsp");
5346 case MM_PLAYER_STATE_PLAYING:
5348 /* NOTE : store current point to overcome some bad operation
5349 *(returning zero when getting current position in paused state) of some
5352 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5353 LOGW("getting current position failed in paused\n");
5355 player->last_position = pos_nsec;
5357 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5358 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5359 This causes problem is position calculation during normal pause resume scenarios also.
5360 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5361 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5362 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5363 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5369 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5370 LOGD("doing async pause in case of ms buff src");
5374 /* pause pipeline */
5375 ret = __mmplayer_gst_pause(player, async);
5377 if (ret != MM_ERROR_NONE)
5378 LOGE("failed to pause player. ret : 0x%x\n", ret);
5380 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5381 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5382 LOGE("failed to update display_rotation");
5390 /* in case of streaming, pause could take long time.*/
5392 _mmplayer_abort_pause(MMHandleType hplayer)
5394 mm_player_t* player = (mm_player_t*)hplayer;
5395 int ret = MM_ERROR_NONE;
5399 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5401 player->pipeline->mainbin,
5402 MM_ERROR_PLAYER_NOT_INITIALIZED);
5404 LOGD("set the pipeline state to READY");
5406 /* set state to READY */
5407 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5408 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5409 if (ret != MM_ERROR_NONE) {
5410 LOGE("fail to change state to READY");
5411 return MM_ERROR_PLAYER_INTERNAL;
5414 LOGD("succeeded in changing state to READY");
5420 _mmplayer_resume(MMHandleType hplayer)
5422 mm_player_t* player = (mm_player_t*)hplayer;
5423 int ret = MM_ERROR_NONE;
5424 gboolean async = FALSE;
5428 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5430 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5431 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5432 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5436 /* Changing back sync mode rtspsrc to async */
5437 LOGD("async resume for rtsp case");
5441 /* check current state */
5442 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5444 ret = __mmplayer_gst_resume(player, async);
5445 if (ret != MM_ERROR_NONE)
5446 LOGE("failed to resume player.\n");
5448 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5449 LOGD("force resume even during buffering");
5450 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5459 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5461 mm_player_t* player = (mm_player_t*)hplayer;
5462 gint64 pos_nsec = 0;
5463 int ret = MM_ERROR_NONE;
5465 signed long long start = 0, stop = 0;
5466 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5469 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5470 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5472 /* The sound of video is not supported under 0.0 and over 2.0. */
5473 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5474 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5477 _mmplayer_set_mute(hplayer, mute);
5479 if (player->playback_rate == rate)
5480 return MM_ERROR_NONE;
5482 /* If the position is reached at start potion during fast backward, EOS is posted.
5483 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5485 player->playback_rate = rate;
5487 current_state = MMPLAYER_CURRENT_STATE(player);
5489 if (current_state != MM_PLAYER_STATE_PAUSED)
5490 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5492 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5494 if ((current_state == MM_PLAYER_STATE_PAUSED)
5495 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5496 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5497 pos_nsec = player->last_position;
5502 stop = GST_CLOCK_TIME_NONE;
5504 start = GST_CLOCK_TIME_NONE;
5508 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5509 player->playback_rate,
5511 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5512 GST_SEEK_TYPE_SET, start,
5513 GST_SEEK_TYPE_SET, stop)) {
5514 LOGE("failed to set speed playback\n");
5515 return MM_ERROR_PLAYER_SEEK;
5518 LOGD("succeeded to set speed playback as %0.1f\n", rate);
5522 return MM_ERROR_NONE;;
5526 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5528 mm_player_t* player = (mm_player_t*)hplayer;
5529 int ret = MM_ERROR_NONE;
5533 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5535 /* check pipline building state */
5536 __mmplayer_check_pipeline(player);
5538 ret = __mmplayer_gst_set_position(player, position, FALSE);
5546 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5548 mm_player_t* player = (mm_player_t*)hplayer;
5549 int ret = MM_ERROR_NONE;
5551 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5553 ret = __mmplayer_gst_get_position(player, position);
5559 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5561 mm_player_t* player = (mm_player_t*)hplayer;
5562 int ret = MM_ERROR_NONE;
5564 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5565 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5567 *duration = player->duration;
5572 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5574 mm_player_t *player = (mm_player_t*)hplayer;
5575 int ret = MM_ERROR_NONE;
5577 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5579 ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5585 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5587 mm_player_t* player = (mm_player_t*)hplayer;
5588 int ret = MM_ERROR_NONE;
5592 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5594 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5602 __mmplayer_is_midi_type(gchar* str_caps)
5604 if ((g_strrstr(str_caps, "audio/midi")) ||
5605 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5606 (g_strrstr(str_caps, "application/x-smaf")) ||
5607 (g_strrstr(str_caps, "audio/x-imelody")) ||
5608 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5609 (g_strrstr(str_caps, "audio/xmf")) ||
5610 (g_strrstr(str_caps, "audio/mxmf"))) {
5619 __mmplayer_is_only_mp3_type(gchar *str_caps)
5621 if (g_strrstr(str_caps, "application/x-id3") ||
5622 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5628 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
5630 GstStructure* caps_structure = NULL;
5631 gint samplerate = 0;
5635 MMPLAYER_RETURN_IF_FAIL(player && caps);
5637 caps_structure = gst_caps_get_structure(caps, 0);
5639 /* set stream information */
5640 gst_structure_get_int(caps_structure, "rate", &samplerate);
5641 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5643 gst_structure_get_int(caps_structure, "channels", &channels);
5644 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5646 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
5650 __mmplayer_update_content_type_info(mm_player_t* player)
5653 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5655 if (__mmplayer_is_midi_type(player->type)) {
5656 player->bypass_audio_effect = TRUE;
5657 } else if (g_strrstr(player->type, "application/x-hls")) {
5658 /* If it can't know exact type when it parses uri because of redirection case,
5659 * it will be fixed by typefinder or when doing autoplugging.
5661 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5662 if (player->streamer) {
5663 player->streamer->is_adaptive_streaming = TRUE;
5664 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5665 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
5667 } else if (g_strrstr(player->type, "application/dash+xml")) {
5668 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5669 if (player->streamer) {
5670 player->streamer->is_adaptive_streaming = TRUE;
5671 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5675 LOGD("uri type : %d", player->profile.uri_type);
5680 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5681 GstCaps *caps, gpointer data)
5683 mm_player_t* player = (mm_player_t*)data;
5688 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5690 /* store type string */
5691 MMPLAYER_FREEIF(player->type);
5692 player->type = gst_caps_to_string(caps);
5694 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
5695 player, player->type, probability, gst_caps_get_size(caps));
5698 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5699 (g_strrstr(player->type, "audio/x-raw-int"))) {
5700 LOGE("not support media format\n");
5702 if (player->msg_posted == FALSE) {
5703 MMMessageParamType msg_param;
5704 memset(&msg_param, 0, sizeof(MMMessageParamType));
5706 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5707 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5709 /* don't post more if one was sent already */
5710 player->msg_posted = TRUE;
5715 __mmplayer_update_content_type_info(player);
5717 pad = gst_element_get_static_pad(tf, "src");
5719 LOGE("fail to get typefind src pad.\n");
5723 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5724 gboolean async = FALSE;
5725 LOGE("failed to autoplug %s\n", player->type);
5727 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5729 if (async && player->msg_posted == FALSE)
5730 __mmplayer_handle_missed_plugin(player);
5736 gst_object_unref(GST_OBJECT(pad));
5744 __mmplayer_gst_make_decodebin(mm_player_t* player)
5746 GstElement *decodebin = NULL;
5750 /* create decodebin */
5751 decodebin = gst_element_factory_make("decodebin", NULL);
5754 LOGE("fail to create decodebin\n");
5758 /* raw pad handling signal */
5759 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5760 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5762 /* no-more-pad pad handling signal */
5763 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5764 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5766 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5767 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5769 /* This signal is emitted when a pad for which there is no further possible
5770 decoding is added to the decodebin.*/
5771 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5772 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5774 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5775 before looking for any elements that can handle that stream.*/
5776 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5777 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5779 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5780 before looking for any elements that can handle that stream.*/
5781 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5782 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5784 /* This signal is emitted once decodebin has finished decoding all the data.*/
5785 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5786 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5788 /* This signal is emitted when a element is added to the bin.*/
5789 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5790 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5797 __mmplayer_gst_make_queue2(mm_player_t *player)
5799 GstElement* queue2 = NULL;
5800 gint64 dur_bytes = 0L;
5801 guint max_buffer_size_bytes = 0;
5802 MMPlayerGstElement *mainbin = NULL;
5803 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5806 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5808 mainbin = player->pipeline->mainbin;
5810 queue2 = gst_element_factory_make("queue2", "queue2");
5812 LOGE("failed to create buffering queue element");
5816 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5817 LOGE("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5819 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5821 if (dur_bytes > 0) {
5822 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
5823 type = MUXED_BUFFER_TYPE_FILE;
5825 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5826 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5832 /* NOTE : in case of ts streaming, player cannot get the correct duration info *
5833 * skip the pull mode(file or ring buffering) setting. */
5834 if (!g_strrstr(player->type, "video/mpegts")) {
5835 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
5836 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
5838 __mm_player_streaming_set_queue2(player->streamer,
5841 max_buffer_size_bytes,
5842 player->ini.http_buffering_time,
5844 player->http_file_buffering_path,
5845 (guint64)dur_bytes);
5852 __mmplayer_gst_create_decoder(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
5854 MMPlayerGstElement* mainbin = NULL;
5855 GstElement* decodebin = NULL;
5856 GstElement* queue2 = NULL;
5857 GstPad* sinkpad = NULL;
5858 GstPad* qsrcpad = NULL;
5859 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
5862 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
5864 mainbin = player->pipeline->mainbin;
5866 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
5868 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
5869 LOGW("need to check: muxed buffer is not null");
5872 queue2 = __mmplayer_gst_make_queue2(player);
5874 LOGE("failed to make queue2");
5878 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
5879 LOGE("failed to add buffering queue");
5883 sinkpad = gst_element_get_static_pad(queue2, "sink");
5884 qsrcpad = gst_element_get_static_pad(queue2, "src");
5886 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
5887 LOGE("failed to link [%s:%s]-[%s:%s]",
5888 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5892 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
5893 LOGE("failed to sync queue2 state with parent");
5897 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
5898 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
5902 gst_object_unref(GST_OBJECT(sinkpad));
5906 /* create decodebin */
5907 decodebin = __mmplayer_gst_make_decodebin(player);
5909 LOGE("failed to make decodebin");
5913 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
5914 LOGE("failed to add decodebin\n");
5918 /* to force caps on the decodebin element and avoid reparsing stuff by
5919 * typefind. It also avoids a deadlock in the way typefind activates pads in
5920 * the state change */
5921 g_object_set(decodebin, "sink-caps", caps, NULL);
5923 sinkpad = gst_element_get_static_pad(decodebin, "sink");
5925 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
5926 LOGE("failed to link [%s:%s]-[%s:%s]",
5927 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5931 gst_object_unref(GST_OBJECT(sinkpad));
5934 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
5935 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
5937 /* set decodebin property about buffer in streaming playback. *
5938 * in case of HLS/DASH, it does not need to have big buffer *
5939 * because it is kind of adaptive streaming. */
5940 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
5941 gdouble high_percent = 0.0;
5943 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
5944 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
5946 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
5947 GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
5949 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
5950 "high-percent", (gint)high_percent,
5951 "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
5952 "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
5953 "max-size-buffers", 0, NULL); // disable or automatic
5956 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
5957 LOGE("failed to sync decodebin state with parent\n");
5968 gst_object_unref(GST_OBJECT(sinkpad));
5971 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
5972 * You need to explicitly set elements to the NULL state before
5973 * dropping the final reference, to allow them to clean up.
5975 gst_element_set_state(queue2, GST_STATE_NULL);
5977 /* And, it still has a parent "player".
5978 * You need to let the parent manage the object instead of unreffing the object directly.
5980 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
5981 gst_object_unref(queue2);
5986 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
5987 * You need to explicitly set elements to the NULL state before
5988 * dropping the final reference, to allow them to clean up.
5990 gst_element_set_state(decodebin, GST_STATE_NULL);
5992 /* And, it still has a parent "player".
5993 * You need to let the parent manage the object instead of unreffing the object directly.
5996 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
5997 gst_object_unref(decodebin);
6005 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
6009 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6010 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6012 LOGD("class : %s, mime : %s \n", factory_class, mime);
6014 /* add missing plugin */
6015 /* NOTE : msl should check missing plugin for image mime type.
6016 * Some motion jpeg clips can have playable audio track.
6017 * So, msl have to play audio after displaying popup written video format not supported.
6019 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6020 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6021 LOGD("not found demuxer\n");
6022 player->not_found_demuxer = TRUE;
6023 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6029 if (!g_strrstr(factory_class, "Demuxer")) {
6030 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6031 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
6032 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6034 /* check that clip have multi tracks or not */
6035 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6036 LOGD("video plugin is already linked\n");
6038 LOGW("add VIDEO to missing plugin\n");
6039 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6040 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6042 } else if (g_str_has_prefix(mime, "audio")) {
6043 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6044 LOGD("audio plugin is already linked\n");
6046 LOGW("add AUDIO to missing plugin\n");
6047 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6048 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6056 return MM_ERROR_NONE;
6061 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6063 mm_player_t* player = (mm_player_t*)data;
6067 MMPLAYER_RETURN_IF_FAIL(player);
6069 /* remove fakesink. */
6070 if (!__mmplayer_gst_remove_fakesink(player,
6071 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6072 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6073 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6074 * source element are not same. To overcome this situation, this function will called
6075 * several places and several times. Therefore, this is not an error case.
6080 LOGD("[handle: %p] pipeline has completely constructed", player);
6082 if ((player->ini.async_start) &&
6083 (player->msg_posted == FALSE) &&
6084 (player->cmd >= MMPLAYER_COMMAND_START))
6085 __mmplayer_handle_missed_plugin(player);
6087 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6091 __mmplayer_check_profile(void)
6094 static int profile_tv = -1;
6096 if (__builtin_expect(profile_tv != -1, 1))
6099 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6100 switch (*profileName) {
6115 __mmplayer_get_next_uri(mm_player_t *player)
6117 MMPlayerParseProfile profile;
6119 guint num_of_list = 0;
6122 num_of_list = g_list_length(player->uri_info.uri_list);
6123 uri_idx = player->uri_info.uri_idx;
6125 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6126 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6127 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6129 LOGW("next uri does not exist");
6133 if (__mmplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
6134 LOGE("failed to parse profile");
6138 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6139 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6140 LOGW("uri type is not supported(%d)", profile.uri_type);
6144 LOGD("success to find next uri %d", uri_idx);
6148 if (uri_idx == num_of_list) {
6149 LOGE("failed to find next uri");
6153 player->uri_info.uri_idx = uri_idx;
6154 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6156 if (mm_attrs_commit_all(player->attrs)) {
6157 LOGE("failed to commit");
6161 SECURE_LOGD("next playback uri: %s", uri);
6166 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6168 #define REPEAT_COUNT_INFINITELY -1
6169 #define REPEAT_COUNT_MIN 2
6171 MMHandleType attrs = 0;
6175 guint num_of_list = 0;
6176 int profile_tv = -1;
6180 LOGD("checking for gapless play option");
6182 if (player->pipeline->textbin) {
6183 LOGE("subtitle path is enabled. gapless play is not supported.\n");
6187 attrs = MMPLAYER_GET_ATTRS(player);
6189 LOGE("fail to get attributes.\n");
6193 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6195 /* gapless playback is not supported in case of video at TV profile. */
6196 profile_tv = __mmplayer_check_profile();
6197 if (profile_tv && video) {
6198 LOGW("not support video gapless playback");
6202 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6203 LOGE("failed to get play count");
6205 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6206 LOGE("failed to get gapless mode");
6208 /* check repeat count in case of audio */
6210 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6211 LOGW("gapless is disabled");
6215 num_of_list = g_list_length(player->uri_info.uri_list);
6217 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6219 if (num_of_list == 0) {
6220 /* audio looping path */
6221 if (count >= REPEAT_COUNT_MIN) {
6222 /* decrease play count */
6223 /* we succeeded to rewind. update play count and then wait for next EOS */
6226 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6228 /* commit attribute */
6229 if (mm_attrs_commit_all(attrs))
6230 LOGE("failed to commit attribute");
6231 } else if (count != REPEAT_COUNT_INFINITELY) {
6232 LOGD("there is no next uri and no repeat");
6236 LOGD("looping cnt %d", count);
6238 /* gapless playback path */
6239 if (!__mmplayer_get_next_uri(player)) {
6240 LOGE("failed to get next uri");
6248 LOGE("unable to play gapless path. EOS will be posted soon");
6253 __mmplayer_initialize_gapless_play(mm_player_t *player)
6259 player->smooth_streaming = FALSE;
6260 player->videodec_linked = 0;
6261 player->audiodec_linked = 0;
6262 player->textsink_linked = 0;
6263 player->is_external_subtitle_present = FALSE;
6264 player->is_external_subtitle_added_now = FALSE;
6265 player->not_supported_codec = MISSING_PLUGIN_NONE;
6266 player->can_support_codec = FOUND_PLUGIN_NONE;
6267 player->pending_seek.is_pending = FALSE;
6268 player->pending_seek.pos = 0;
6269 player->msg_posted = FALSE;
6270 player->has_many_types = FALSE;
6271 player->no_more_pad = FALSE;
6272 player->not_found_demuxer = 0;
6273 player->seek_state = MMPLAYER_SEEK_NONE;
6274 player->is_subtitle_force_drop = FALSE;
6275 player->play_subtitle = FALSE;
6276 player->adjust_subtitle_pos = 0;
6278 player->total_bitrate = 0;
6279 player->total_maximum_bitrate = 0;
6281 __mmplayer_track_initialize(player);
6282 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6284 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6285 player->bitrate[i] = 0;
6286 player->maximum_bitrate[i] = 0;
6289 if (player->v_stream_caps) {
6290 gst_caps_unref(player->v_stream_caps);
6291 player->v_stream_caps = NULL;
6294 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6296 /* clean found parsers */
6297 if (player->parsers) {
6298 GList *parsers = player->parsers;
6299 for (; parsers; parsers = g_list_next(parsers)) {
6300 gchar *name = parsers->data;
6301 MMPLAYER_FREEIF(name);
6303 g_list_free(player->parsers);
6304 player->parsers = NULL;
6307 /* clean found audio decoders */
6308 if (player->audio_decoders) {
6309 GList *a_dec = player->audio_decoders;
6310 for (; a_dec; a_dec = g_list_next(a_dec)) {
6311 gchar *name = a_dec->data;
6312 MMPLAYER_FREEIF(name);
6314 g_list_free(player->audio_decoders);
6315 player->audio_decoders = NULL;
6322 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6324 MMPlayerGstElement *mainbin = NULL;
6325 MMMessageParamType msg_param = {0,};
6326 GstElement *element = NULL;
6327 MMHandleType attrs = 0;
6329 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6333 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6334 LOGE("player is not initialized");
6338 mainbin = player->pipeline->mainbin;
6339 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6341 attrs = MMPLAYER_GET_ATTRS(player);
6343 LOGE("fail to get attributes");
6347 /* Initialize Player values */
6348 __mmplayer_initialize_gapless_play(player);
6350 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6352 if (__mmplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6353 LOGE("failed to parse profile");
6354 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6358 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6359 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6360 LOGE("dash or hls is not supportable");
6361 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6365 element = __mmplayer_gst_create_source(player);
6367 LOGE("no source element was created");
6371 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6372 LOGE("failed to add source element to pipeline");
6373 gst_object_unref(GST_OBJECT(element));
6378 /* take source element */
6379 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6380 mainbin[MMPLAYER_M_SRC].gst = element;
6384 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6385 if (player->streamer == NULL) {
6386 player->streamer = __mm_player_streaming_create();
6387 __mm_player_streaming_initialize(player->streamer);
6390 elem_idx = MMPLAYER_M_TYPEFIND;
6391 element = gst_element_factory_make("typefind", "typefinder");
6392 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6393 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6395 elem_idx = MMPLAYER_M_AUTOPLUG;
6396 element = __mmplayer_gst_make_decodebin(player);
6399 /* check autoplug element is OK */
6401 LOGE("can not create element(%d)", elem_idx);
6405 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6406 LOGE("failed to add sinkbin to pipeline");
6407 gst_object_unref(GST_OBJECT(element));
6412 mainbin[elem_idx].id = elem_idx;
6413 mainbin[elem_idx].gst = element;
6415 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6416 LOGE("Failed to link src - autoplug(or typefind)");
6420 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6421 LOGE("Failed to change state of src element");
6425 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6426 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6427 LOGE("Failed to change state of decodebin");
6431 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6432 LOGE("Failed to change state of src element");
6437 player->gapless.stream_changed = TRUE;
6438 player->gapless.running = TRUE;
6444 MMPLAYER_PLAYBACK_UNLOCK(player);
6446 if (!player->msg_posted) {
6447 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6448 player->msg_posted = TRUE;
6455 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6457 mm_player_selector_t *selector = &player->selector[type];
6458 MMPlayerGstElement *sinkbin = NULL;
6459 enum MainElementID selectorId = MMPLAYER_M_NUM;
6460 enum MainElementID sinkId = MMPLAYER_M_NUM;
6461 GstPad *srcpad = NULL;
6462 GstPad *sinkpad = NULL;
6463 gboolean send_notice = FALSE;
6466 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6468 LOGD("type %d", type);
6471 case MM_PLAYER_TRACK_TYPE_AUDIO:
6472 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6473 sinkId = MMPLAYER_A_BIN;
6474 sinkbin = player->pipeline->audiobin;
6476 case MM_PLAYER_TRACK_TYPE_VIDEO:
6477 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6478 sinkId = MMPLAYER_V_BIN;
6479 sinkbin = player->pipeline->videobin;
6482 case MM_PLAYER_TRACK_TYPE_TEXT:
6483 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6484 sinkId = MMPLAYER_T_BIN;
6485 sinkbin = player->pipeline->textbin;
6488 LOGE("requested type is not supportable");
6493 if (player->pipeline->mainbin[selectorId].gst) {
6496 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6498 if (selector->event_probe_id != 0)
6499 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6500 selector->event_probe_id = 0;
6502 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6503 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6505 if (srcpad && sinkpad) {
6506 /* after getting drained signal there is no data flows, so no need to do pad_block */
6507 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6508 gst_pad_unlink(srcpad, sinkpad);
6510 /* send custom event to sink pad to handle it at video sink */
6512 LOGD("send custom event to sinkpad");
6513 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6514 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6515 gst_pad_send_event(sinkpad, event);
6519 gst_object_unref(sinkpad);
6522 gst_object_unref(srcpad);
6525 LOGD("selector release");
6527 /* release and unref requests pad from the selector */
6528 for (n = 0; n < selector->channels->len; n++) {
6529 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6530 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6532 g_ptr_array_set_size(selector->channels, 0);
6534 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6535 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6537 player->pipeline->mainbin[selectorId].gst = NULL;
6545 __mmplayer_deactivate_old_path(mm_player_t *player)
6548 MMPLAYER_RETURN_IF_FAIL(player);
6550 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6551 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6552 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6553 LOGE("deactivate selector error");
6557 __mmplayer_track_destroy(player);
6558 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6560 if (player->streamer) {
6561 __mm_player_streaming_deinitialize(player->streamer);
6562 __mm_player_streaming_destroy(player->streamer);
6563 player->streamer = NULL;
6566 MMPLAYER_PLAYBACK_LOCK(player);
6567 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6574 if (!player->msg_posted) {
6575 MMMessageParamType msg = {0,};
6578 msg.code = MM_ERROR_PLAYER_INTERNAL;
6579 LOGE("gapless_uri_play> deactivate error");
6581 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6582 player->msg_posted = TRUE;
6587 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
6589 int result = MM_ERROR_NONE;
6590 mm_player_t* player = (mm_player_t*) hplayer;
6593 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6596 player->http_file_buffering_path = (gchar*)file_path;
6597 LOGD("temp file path: %s\n", player->http_file_buffering_path);
6603 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
6605 int result = MM_ERROR_NONE;
6606 mm_player_t* player = (mm_player_t*) hplayer;
6609 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6611 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6612 if (mm_attrs_commit_all(player->attrs)) {
6613 LOGE("failed to commit the original uri.\n");
6614 result = MM_ERROR_PLAYER_INTERNAL;
6616 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6617 LOGE("failed to add the original uri in the uri list.\n");
6624 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
6626 mm_player_t* player = (mm_player_t*) hplayer;
6627 guint num_of_list = 0;
6631 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6632 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6634 if (player->pipeline && player->pipeline->textbin) {
6635 LOGE("subtitle path is enabled.\n");
6636 return MM_ERROR_PLAYER_INVALID_STATE;
6639 num_of_list = g_list_length(player->uri_info.uri_list);
6641 if (is_first_path == TRUE) {
6642 if (num_of_list == 0) {
6643 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6644 LOGD("add original path : %s", uri);
6646 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6647 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6649 LOGD("change original path : %s", uri);
6652 MMHandleType attrs = 0;
6653 attrs = MMPLAYER_GET_ATTRS(player);
6655 if (num_of_list == 0) {
6656 char *original_uri = NULL;
6659 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6661 if (!original_uri) {
6662 LOGE("there is no original uri.");
6663 return MM_ERROR_PLAYER_INVALID_STATE;
6666 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6667 player->uri_info.uri_idx = 0;
6669 LOGD("add original path at first : %s", original_uri);
6673 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6674 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6678 return MM_ERROR_NONE;
6681 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
6683 mm_player_t* player = (mm_player_t*) hplayer;
6684 char *next_uri = NULL;
6685 guint num_of_list = 0;
6688 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6690 num_of_list = g_list_length(player->uri_info.uri_list);
6692 if (num_of_list > 0) {
6693 gint uri_idx = player->uri_info.uri_idx;
6695 if (uri_idx < num_of_list-1)
6700 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6701 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
6703 *uri = g_strdup(next_uri);
6707 return MM_ERROR_NONE;
6711 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
6712 GstCaps *caps, gpointer data)
6714 mm_player_t* player = (mm_player_t*)data;
6715 const gchar* klass = NULL;
6716 const gchar* mime = NULL;
6717 gchar* caps_str = NULL;
6719 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6720 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6721 caps_str = gst_caps_to_string(caps);
6723 LOGW("unknown type of caps : %s from %s",
6724 caps_str, GST_ELEMENT_NAME(elem));
6726 MMPLAYER_FREEIF(caps_str);
6728 /* There is no available codec. */
6729 __mmplayer_check_not_supported_codec(player, klass, mime);
6733 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
6734 GstCaps * caps, gpointer data)
6736 mm_player_t* player = (mm_player_t*)data;
6737 const char* mime = NULL;
6738 gboolean ret = TRUE;
6740 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6741 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6743 if (g_str_has_prefix(mime, "audio")) {
6744 GstStructure* caps_structure = NULL;
6745 gint samplerate = 0;
6747 gchar *caps_str = NULL;
6749 caps_structure = gst_caps_get_structure(caps, 0);
6750 gst_structure_get_int(caps_structure, "rate", &samplerate);
6751 gst_structure_get_int(caps_structure, "channels", &channels);
6753 if ((channels > 0 && samplerate == 0)) {
6754 LOGD("exclude audio...");
6758 caps_str = gst_caps_to_string(caps);
6759 /* set it directly because not sent by TAG */
6760 if (g_strrstr(caps_str, "mobile-xmf"))
6761 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6762 MMPLAYER_FREEIF(caps_str);
6763 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6764 MMMessageParamType msg_param;
6765 memset(&msg_param, 0, sizeof(MMMessageParamType));
6766 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6767 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6768 LOGD("video file is not supported on this device");
6770 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6771 LOGD("already video linked");
6774 LOGD("found new stream");
6781 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
6783 int ret = MM_ERROR_NONE;
6785 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6787 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6788 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6790 LOGD("audio codec type: %d", codec_type);
6791 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6792 /* sw codec will be skipped */
6793 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6794 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6795 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6796 ret = MM_ERROR_PLAYER_INTERNAL;
6800 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6801 /* hw codec will be skipped */
6802 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6803 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6804 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6805 ret = MM_ERROR_PLAYER_INTERNAL;
6810 /* set stream information */
6811 if (!player->audiodec_linked)
6812 __mmplayer_set_audio_attrs(player, caps);
6814 /* update codec info */
6815 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6816 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6817 player->audiodec_linked = 1;
6819 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6821 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6823 LOGD("video codec type: %d", codec_type);
6824 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6825 /* sw codec is skipped */
6826 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
6827 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
6828 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
6829 ret = MM_ERROR_PLAYER_INTERNAL;
6833 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6834 /* hw codec is skipped */
6835 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
6836 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
6837 ret = MM_ERROR_PLAYER_INTERNAL;
6842 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
6843 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
6845 /* mark video decoder for acquire */
6846 if (player->video_decoder_resource == NULL) {
6847 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
6848 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
6849 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
6850 &player->video_decoder_resource)
6851 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6852 LOGE("could not mark video_decoder resource for acquire");
6853 ret = MM_ERROR_PLAYER_INTERNAL;
6857 LOGW("video decoder resource is already acquired, skip it.");
6858 ret = MM_ERROR_PLAYER_INTERNAL;
6862 player->interrupted_by_resource = FALSE;
6863 /* acquire resources for video playing */
6864 if (mm_resource_manager_commit(player->resource_manager)
6865 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6866 LOGE("could not acquire resources for video decoding\n");
6867 ret = MM_ERROR_PLAYER_INTERNAL;
6872 /* update codec info */
6873 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
6874 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
6875 player->videodec_linked = 1;
6883 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
6884 GstCaps* caps, GstElementFactory* factory, gpointer data)
6886 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
6887 We are defining our own and will be removed when it actually exposed */
6889 GST_AUTOPLUG_SELECT_TRY,
6890 GST_AUTOPLUG_SELECT_EXPOSE,
6891 GST_AUTOPLUG_SELECT_SKIP
6892 } GstAutoplugSelectResult;
6894 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
6895 mm_player_t* player = (mm_player_t*)data;
6897 gchar* factory_name = NULL;
6898 gchar* caps_str = NULL;
6899 const gchar* klass = NULL;
6902 factory_name = GST_OBJECT_NAME(factory);
6903 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
6904 caps_str = gst_caps_to_string(caps);
6906 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
6908 /* store type string */
6909 if (player->type == NULL) {
6910 player->type = gst_caps_to_string(caps);
6911 __mmplayer_update_content_type_info(player);
6914 /* filtering exclude keyword */
6915 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
6916 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
6917 LOGW("skipping [%s] by exculde keyword [%s]",
6918 factory_name, player->ini.exclude_element_keyword[idx]);
6920 result = GST_AUTOPLUG_SELECT_SKIP;
6925 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
6926 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
6927 LOGW("skipping [%s] by unsupported codec keyword [%s]",
6928 factory_name, player->ini.unsupported_codec_keyword[idx]);
6929 result = GST_AUTOPLUG_SELECT_SKIP;
6934 /* exclude webm format */
6935 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
6936 * because webm format is not supportable.
6937 * If webm is disabled in "autoplug-continue", there is no state change
6938 * failure or error because the decodebin will expose the pad directly.
6939 * It make MSL invoke _prepare_async_callback.
6940 * So, we need to disable webm format in "autoplug-select" */
6941 if (caps_str && strstr(caps_str, "webm")) {
6942 LOGW("webm is not supported");
6943 result = GST_AUTOPLUG_SELECT_SKIP;
6947 /* check factory class for filtering */
6948 /* NOTE : msl don't need to use image plugins.
6949 * So, those plugins should be skipped for error handling.
6951 if (g_strrstr(klass, "Codec/Decoder/Image")) {
6952 LOGD("skipping [%s] by not required\n", factory_name);
6953 result = GST_AUTOPLUG_SELECT_SKIP;
6957 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
6958 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
6959 // TO CHECK : subtitle if needed, add subparse exception.
6960 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
6961 result = GST_AUTOPLUG_SELECT_SKIP;
6965 if (g_strrstr(factory_name, "mpegpsdemux")) {
6966 LOGD("skipping PS container - not support\n");
6967 result = GST_AUTOPLUG_SELECT_SKIP;
6971 if (g_strrstr(factory_name, "mssdemux"))
6972 player->smooth_streaming = TRUE;
6974 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
6975 (g_strrstr(klass, "Codec/Decoder/Video"))) {
6978 GstStructure *str = NULL;
6979 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
6981 /* don't make video because of not required */
6982 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
6983 (!player->set_mode.media_packet_video_stream)) {
6984 LOGD("no need video decoding, expose pad");
6985 result = GST_AUTOPLUG_SELECT_EXPOSE;
6989 /* get w/h for omx state-tune */
6990 /* FIXME: deprecated? */
6991 str = gst_caps_get_structure(caps, 0);
6992 gst_structure_get_int(str, "width", &width);
6995 if (player->v_stream_caps) {
6996 gst_caps_unref(player->v_stream_caps);
6997 player->v_stream_caps = NULL;
7000 player->v_stream_caps = gst_caps_copy(caps);
7001 LOGD("take caps for video state tune");
7002 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7006 if (g_strrstr(klass, "Codec/Decoder")) {
7007 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
7008 LOGD("skipping %s codec", factory_name);
7009 result = GST_AUTOPLUG_SELECT_SKIP;
7015 MMPLAYER_FREEIF(caps_str);
7021 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
7024 //mm_player_t* player = (mm_player_t*)data;
7025 GstCaps* caps = NULL;
7027 LOGD("[Decodebin2] pad-removed signal\n");
7029 caps = gst_pad_query_caps(new_pad, NULL);
7031 gchar* caps_str = NULL;
7032 caps_str = gst_caps_to_string(caps);
7034 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7036 MMPLAYER_FREEIF(caps_str);
7037 gst_caps_unref(caps);
7042 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7044 mm_player_t* player = (mm_player_t*)data;
7045 GstIterator *iter = NULL;
7046 GValue item = { 0, };
7048 gboolean done = FALSE;
7049 gboolean is_all_drained = TRUE;
7052 MMPLAYER_RETURN_IF_FAIL(player);
7054 LOGD("__mmplayer_gst_decode_drained");
7056 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7057 LOGW("Fail to get cmd lock");
7061 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7062 !__mmplayer_verify_gapless_play_path(player)) {
7063 LOGD("decoding is finished.");
7064 __mmplayer_reset_gapless_state(player);
7065 MMPLAYER_CMD_UNLOCK(player);
7069 player->gapless.reconfigure = TRUE;
7071 /* check decodebin src pads whether they received EOS or not */
7072 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7075 switch (gst_iterator_next(iter, &item)) {
7076 case GST_ITERATOR_OK:
7077 pad = g_value_get_object(&item);
7078 if (pad && !GST_PAD_IS_EOS(pad)) {
7079 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7080 is_all_drained = FALSE;
7083 g_value_reset(&item);
7085 case GST_ITERATOR_RESYNC:
7086 gst_iterator_resync(iter);
7088 case GST_ITERATOR_ERROR:
7089 case GST_ITERATOR_DONE:
7094 g_value_unset(&item);
7095 gst_iterator_free(iter);
7097 if (!is_all_drained) {
7098 LOGD("Wait util the all pads get EOS.");
7099 MMPLAYER_CMD_UNLOCK(player);
7104 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7105 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7107 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7108 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7109 __mmplayer_deactivate_old_path(player);
7110 MMPLAYER_CMD_UNLOCK(player);
7116 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7118 mm_player_t* player = (mm_player_t*)data;
7119 const gchar* klass = NULL;
7120 gchar* factory_name = NULL;
7122 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7123 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7125 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
7127 if (__mmplayer_add_dump_buffer_probe(player, element))
7128 LOGD("add buffer probe");
7131 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7132 gchar* selected = NULL;
7133 selected = g_strdup(GST_ELEMENT_NAME(element));
7134 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7138 if (g_strrstr(klass, "Parser")) {
7139 gchar* selected = NULL;
7141 selected = g_strdup(factory_name);
7142 player->parsers = g_list_append(player->parsers, selected);
7145 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7146 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7147 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7149 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7150 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7152 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7153 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7154 "max-video-width", player->adaptive_info.limit.width,
7155 "max-video-height", player->adaptive_info.limit.height, NULL);
7157 } else if (g_strrstr(klass, "Demuxer")) {
7158 //LOGD("plugged element is demuxer. take it");
7159 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7160 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7163 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7164 int surface_type = 0;
7166 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7169 // to support trust-zone only
7170 if (g_strrstr(factory_name, "asfdemux")) {
7171 LOGD("set file-location %s\n", player->profile.uri);
7172 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7173 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7174 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
7175 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7176 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7177 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7178 (__mmplayer_is_only_mp3_type(player->type))) {
7179 LOGD("[mpegaudioparse] set streaming pull mode.");
7180 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7182 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7183 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7186 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7187 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7188 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7190 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7191 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7193 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7194 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7195 (MMPLAYER_IS_DASH_STREAMING(player))) {
7196 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7197 __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time);
7198 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7207 __mmplayer_release_misc(mm_player_t* player)
7210 bool cur_mode = player->set_mode.rich_audio;
7213 MMPLAYER_RETURN_IF_FAIL(player);
7215 player->video_stream_cb = NULL;
7216 player->video_stream_cb_user_param = NULL;
7217 player->video_stream_prerolled = FALSE;
7219 player->audio_stream_render_cb = NULL;
7220 player->audio_stream_cb_user_param = NULL;
7221 player->audio_stream_sink_sync = false;
7223 player->video_stream_changed_cb = NULL;
7224 player->video_stream_changed_cb_user_param = NULL;
7226 player->audio_stream_changed_cb = NULL;
7227 player->audio_stream_changed_cb_user_param = NULL;
7229 player->sent_bos = FALSE;
7230 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7232 player->seek_state = MMPLAYER_SEEK_NONE;
7234 player->total_bitrate = 0;
7235 player->total_maximum_bitrate = 0;
7237 player->not_found_demuxer = 0;
7239 player->last_position = 0;
7240 player->duration = 0;
7241 player->http_content_size = 0;
7242 player->not_supported_codec = MISSING_PLUGIN_NONE;
7243 player->can_support_codec = FOUND_PLUGIN_NONE;
7244 player->pending_seek.is_pending = FALSE;
7245 player->pending_seek.pos = 0;
7246 player->msg_posted = FALSE;
7247 player->has_many_types = FALSE;
7248 player->is_subtitle_force_drop = FALSE;
7249 player->play_subtitle = FALSE;
7250 player->adjust_subtitle_pos = 0;
7251 player->last_multiwin_status = FALSE;
7252 player->has_closed_caption = FALSE;
7253 player->set_mode.media_packet_video_stream = false;
7254 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7255 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7257 player->set_mode.rich_audio = cur_mode;
7259 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7260 player->bitrate[i] = 0;
7261 player->maximum_bitrate[i] = 0;
7264 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7266 /* remove media stream cb(appsrc cb) */
7267 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7268 player->media_stream_buffer_status_cb[i] = NULL;
7269 player->media_stream_seek_data_cb[i] = NULL;
7270 player->buffer_cb_user_param[i] = NULL;
7271 player->seek_cb_user_param[i] = NULL;
7273 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7275 /* free memory related to audio effect */
7276 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7278 if (player->adaptive_info.var_list) {
7279 g_list_free_full(player->adaptive_info.var_list, g_free);
7280 player->adaptive_info.var_list = NULL;
7283 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7284 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7285 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7287 /* Reset video360 settings to their defaults in case if the pipeline is to be
7290 player->video360_metadata.is_spherical = -1;
7291 player->is_openal_plugin_used = FALSE;
7293 player->is_content_spherical = FALSE;
7294 player->is_video360_enabled = TRUE;
7295 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7296 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7297 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7298 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7299 player->video360_zoom = 1.0f;
7300 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7301 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7303 player->sound.rg_enable = false;
7305 __mmplayer_initialize_video_roi(player);
7310 __mmplayer_release_misc_post(mm_player_t* player)
7312 char *original_uri = NULL;
7315 /* player->pipeline is already released before. */
7317 MMPLAYER_RETURN_IF_FAIL(player);
7319 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7321 /* clean found parsers */
7322 if (player->parsers) {
7323 GList *parsers = player->parsers;
7324 for (; parsers; parsers = g_list_next(parsers)) {
7325 gchar *name = parsers->data;
7326 MMPLAYER_FREEIF(name);
7328 g_list_free(player->parsers);
7329 player->parsers = NULL;
7332 /* clean found audio decoders */
7333 if (player->audio_decoders) {
7334 GList *a_dec = player->audio_decoders;
7335 for (; a_dec; a_dec = g_list_next(a_dec)) {
7336 gchar *name = a_dec->data;
7337 MMPLAYER_FREEIF(name);
7339 g_list_free(player->audio_decoders);
7340 player->audio_decoders = NULL;
7343 /* clean the uri list except original uri */
7344 if (player->uri_info.uri_list) {
7345 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7347 if (player->attrs) {
7348 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7349 LOGD("restore original uri = %s\n", original_uri);
7351 if (mm_attrs_commit_all(player->attrs))
7352 LOGE("failed to commit the original uri.\n");
7355 GList *uri_list = player->uri_info.uri_list;
7356 for (; uri_list; uri_list = g_list_next(uri_list)) {
7357 gchar *uri = uri_list->data;
7358 MMPLAYER_FREEIF(uri);
7360 g_list_free(player->uri_info.uri_list);
7361 player->uri_info.uri_list = NULL;
7364 /* clear the audio stream buffer list */
7365 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7367 /* clear the video stream bo list */
7368 __mmplayer_video_stream_destroy_bo_list(player);
7369 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7371 if (player->profile.input_mem.buf) {
7372 free(player->profile.input_mem.buf);
7373 player->profile.input_mem.buf = NULL;
7375 player->profile.input_mem.len = 0;
7376 player->profile.input_mem.offset = 0;
7378 player->uri_info.uri_idx = 0;
7383 __mmplayer_check_subtitle(mm_player_t* player)
7385 MMHandleType attrs = 0;
7386 char *subtitle_uri = NULL;
7390 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7392 /* get subtitle attribute */
7393 attrs = MMPLAYER_GET_ATTRS(player);
7397 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7398 if (!subtitle_uri || !strlen(subtitle_uri))
7401 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7402 player->is_external_subtitle_present = TRUE;
7410 __mmplayer_cancel_eos_timer(mm_player_t* player)
7412 MMPLAYER_RETURN_IF_FAIL(player);
7414 if (player->eos_timer) {
7415 LOGD("cancel eos timer");
7416 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7417 player->eos_timer = 0;
7424 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
7428 MMPLAYER_RETURN_IF_FAIL(player);
7429 MMPLAYER_RETURN_IF_FAIL(sink);
7431 player->sink_elements =
7432 g_list_append(player->sink_elements, sink);
7438 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
7442 MMPLAYER_RETURN_IF_FAIL(player);
7443 MMPLAYER_RETURN_IF_FAIL(sink);
7445 player->sink_elements =
7446 g_list_remove(player->sink_elements, sink);
7452 __mmplayer_add_signal_connection(mm_player_t* player, GObject* object,
7453 MMPlayerSignalType type, const gchar* signal, GCallback cb_funct, gpointer u_data)
7455 MMPlayerSignalItem* item = NULL;
7458 MMPLAYER_RETURN_IF_FAIL(player);
7460 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7461 LOGE("invalid signal type [%d]", type);
7465 item = (MMPlayerSignalItem*)g_malloc(sizeof(MMPlayerSignalItem));
7467 LOGE("cannot connect signal [%s]", signal);
7472 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7473 player->signals[type] = g_list_append(player->signals[type], item);
7479 /* NOTE : be careful with calling this api. please refer to below glib comment
7480 * glib comment : Note that there is a bug in GObject that makes this function much
7481 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7482 * will no longer be called, but, the signal handler is not currently disconnected.
7483 * If the instance is itself being freed at the same time than this doesn't matter,
7484 * since the signal will automatically be removed, but if instance persists,
7485 * then the signal handler will leak. You should not remove the signal yourself
7486 * because in a future versions of GObject, the handler will automatically be
7489 * It's possible to work around this problem in a way that will continue to work
7490 * with future versions of GObject by checking that the signal handler is still
7491 * connected before disconnected it:
7493 * if (g_signal_handler_is_connected(instance, id))
7494 * g_signal_handler_disconnect(instance, id);
7497 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
7499 GList* sig_list = NULL;
7500 MMPlayerSignalItem* item = NULL;
7504 MMPLAYER_RETURN_IF_FAIL(player);
7506 LOGD("release signals type : %d", type);
7508 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7509 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7510 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7511 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7512 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7513 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7517 sig_list = player->signals[type];
7519 for (; sig_list; sig_list = sig_list->next) {
7520 item = sig_list->data;
7522 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7523 if (g_signal_handler_is_connected(item->obj, item->sig))
7524 g_signal_handler_disconnect(item->obj, item->sig);
7527 MMPLAYER_FREEIF(item);
7530 g_list_free(player->signals[type]);
7531 player->signals[type] = NULL;
7538 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7540 mm_player_t* player = 0;
7541 int prev_display_surface_type = 0;
7542 void *prev_display_overlay = NULL;
7546 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7547 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7549 player = MM_PLAYER_CAST(handle);
7551 /* check video sinkbin is created */
7552 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7553 LOGE("Videosink is already created");
7554 return MM_ERROR_NONE;
7557 LOGD("videosink element is not yet ready");
7559 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7560 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7562 return MM_ERROR_INVALID_ARGUMENT;
7565 /* load previous attributes */
7566 if (player->attrs) {
7567 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7568 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7569 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7570 if (prev_display_surface_type == surface_type) {
7571 LOGD("incoming display surface type is same as previous one, do nothing..");
7573 return MM_ERROR_NONE;
7576 LOGE("failed to load attributes");
7578 return MM_ERROR_PLAYER_INTERNAL;
7581 /* videobin is not created yet, so we just set attributes related to display surface */
7582 LOGD("store display attribute for given surface type(%d)", surface_type);
7583 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7584 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7585 if (mm_attrs_commit_all(player->attrs)) {
7586 LOGE("failed to commit attribute");
7588 return MM_ERROR_PLAYER_INTERNAL;
7592 return MM_ERROR_NONE;
7595 /* Note : if silent is true, then subtitle would not be displayed. :*/
7596 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7598 mm_player_t* player = (mm_player_t*) hplayer;
7602 /* check player handle */
7603 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7605 player->set_mode.subtitle_off = silent;
7607 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
7611 return MM_ERROR_NONE;
7614 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
7616 MMPlayerGstElement* mainbin = NULL;
7617 MMPlayerGstElement* textbin = NULL;
7618 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7619 GstState current_state = GST_STATE_VOID_PENDING;
7620 GstState element_state = GST_STATE_VOID_PENDING;
7621 GstState element_pending_state = GST_STATE_VOID_PENDING;
7623 GstEvent *event = NULL;
7624 int result = MM_ERROR_NONE;
7626 GstClock *curr_clock = NULL;
7627 GstClockTime base_time, start_time, curr_time;
7632 /* check player handle */
7633 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7635 player->pipeline->mainbin &&
7636 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7638 mainbin = player->pipeline->mainbin;
7639 textbin = player->pipeline->textbin;
7641 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7643 // sync clock with current pipeline
7644 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7645 curr_time = gst_clock_get_time(curr_clock);
7647 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7648 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7650 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7651 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7653 if (current_state > GST_STATE_READY) {
7654 // sync state with current pipeline
7655 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7656 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7657 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7659 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7660 if (GST_STATE_CHANGE_FAILURE == ret) {
7661 LOGE("fail to state change.\n");
7662 result = MM_ERROR_PLAYER_INTERNAL;
7666 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7667 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7670 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7671 gst_object_unref(curr_clock);
7674 // seek to current position
7675 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7676 result = MM_ERROR_PLAYER_INVALID_STATE;
7677 LOGE("gst_element_query_position failed, invalid state\n");
7681 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7682 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
7684 __mmplayer_gst_send_event_to_sink(player, event);
7686 result = MM_ERROR_PLAYER_INTERNAL;
7687 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7691 /* sync state with current pipeline */
7692 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7693 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7694 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7696 return MM_ERROR_NONE;
7699 /* release text pipeline resource */
7700 player->textsink_linked = 0;
7702 /* release signal */
7703 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7705 /* release textbin with it's childs */
7706 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7707 MMPLAYER_FREEIF(player->pipeline->textbin);
7708 player->pipeline->textbin = NULL;
7710 /* release subtitle elem */
7711 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7712 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7718 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
7720 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7721 GstState current_state = GST_STATE_VOID_PENDING;
7723 MMHandleType attrs = 0;
7724 MMPlayerGstElement* mainbin = NULL;
7725 MMPlayerGstElement* textbin = NULL;
7727 gchar* subtitle_uri = NULL;
7728 int result = MM_ERROR_NONE;
7729 const gchar *charset = NULL;
7733 /* check player handle */
7734 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7736 player->pipeline->mainbin &&
7737 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7738 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7740 mainbin = player->pipeline->mainbin;
7741 textbin = player->pipeline->textbin;
7743 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7744 if (current_state < GST_STATE_READY) {
7745 result = MM_ERROR_PLAYER_INVALID_STATE;
7746 LOGE("Pipeline is not in proper state\n");
7750 attrs = MMPLAYER_GET_ATTRS(player);
7752 LOGE("cannot get content attribute\n");
7753 result = MM_ERROR_PLAYER_INTERNAL;
7757 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7758 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7759 LOGE("subtitle uri is not proper filepath\n");
7760 result = MM_ERROR_PLAYER_INVALID_URI;
7764 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7765 LOGE("failed to get storage info of subtitle path");
7766 result = MM_ERROR_PLAYER_INVALID_URI;
7770 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
7771 LOGD("new subtitle file path is [%s]\n", filepath);
7773 if (!strcmp(filepath, subtitle_uri)) {
7774 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
7777 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7778 if (mm_attrs_commit_all(player->attrs)) {
7779 LOGE("failed to commit.\n");
7784 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7785 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7786 player->subtitle_language_list = NULL;
7787 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7789 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7790 if (ret != GST_STATE_CHANGE_SUCCESS) {
7791 LOGE("failed to change state of textbin to READY");
7792 result = MM_ERROR_PLAYER_INTERNAL;
7796 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7797 if (ret != GST_STATE_CHANGE_SUCCESS) {
7798 LOGE("failed to change state of subparse to READY");
7799 result = MM_ERROR_PLAYER_INTERNAL;
7803 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7804 if (ret != GST_STATE_CHANGE_SUCCESS) {
7805 LOGE("failed to change state of filesrc to READY");
7806 result = MM_ERROR_PLAYER_INTERNAL;
7810 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7812 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7814 charset = util_get_charset(filepath);
7816 LOGD("detected charset is %s\n", charset);
7817 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7820 result = _mmplayer_sync_subtitle_pipeline(player);
7827 /* API to switch between external subtitles */
7828 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
7830 int result = MM_ERROR_NONE;
7831 mm_player_t* player = (mm_player_t*)hplayer;
7836 /* check player handle */
7837 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7839 /* filepath can be null in idle state */
7841 /* check file path */
7842 if ((path = strstr(filepath, "file://")))
7843 result = util_exist_file_path(path + 7);
7845 result = util_exist_file_path(filepath);
7847 if (result != MM_ERROR_NONE) {
7848 LOGE("invalid subtitle path 0x%X", result);
7849 return result; /* file not found or permission denied */
7853 if (!player->pipeline) {
7855 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7856 if (mm_attrs_commit_all(player->attrs)) {
7857 LOGE("failed to commit"); /* subtitle path will not be created */
7858 return MM_ERROR_PLAYER_INTERNAL;
7861 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7862 /* check filepath */
7863 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7865 if (!__mmplayer_check_subtitle(player)) {
7866 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7867 if (mm_attrs_commit_all(player->attrs)) {
7868 LOGE("failed to commit");
7869 return MM_ERROR_PLAYER_INTERNAL;
7872 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
7873 LOGE("fail to create text pipeline");
7874 return MM_ERROR_PLAYER_INTERNAL;
7877 result = _mmplayer_sync_subtitle_pipeline(player);
7879 result = __mmplayer_change_external_subtitle_language(player, filepath);
7882 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
7883 player->is_external_subtitle_added_now = TRUE;
7885 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7886 if (!player->subtitle_language_list) {
7887 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
7888 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
7889 LOGW("subtitle language list is not updated yet");
7891 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7899 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
7901 int result = MM_ERROR_NONE;
7902 gchar* change_pad_name = NULL;
7903 GstPad* sinkpad = NULL;
7904 MMPlayerGstElement* mainbin = NULL;
7905 enum MainElementID elem_idx = MMPLAYER_M_NUM;
7906 GstCaps* caps = NULL;
7907 gint total_track_num = 0;
7911 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
7912 MM_ERROR_PLAYER_NOT_INITIALIZED);
7914 LOGD("Change Track(%d) to %d\n", type, index);
7916 mainbin = player->pipeline->mainbin;
7918 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
7919 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
7920 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
7921 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
7923 /* Changing Video Track is not supported. */
7924 LOGE("Track Type Error\n");
7928 if (mainbin[elem_idx].gst == NULL) {
7929 result = MM_ERROR_PLAYER_NO_OP;
7930 LOGD("Req track doesn't exist\n");
7934 total_track_num = player->selector[type].total_track_num;
7935 if (total_track_num <= 0) {
7936 result = MM_ERROR_PLAYER_NO_OP;
7937 LOGD("Language list is not available \n");
7941 if ((index < 0) || (index >= total_track_num)) {
7942 result = MM_ERROR_INVALID_ARGUMENT;
7943 LOGD("Not a proper index : %d \n", index);
7947 /*To get the new pad from the selector*/
7948 change_pad_name = g_strdup_printf("sink_%u", index);
7949 if (change_pad_name == NULL) {
7950 result = MM_ERROR_PLAYER_INTERNAL;
7951 LOGD("Pad does not exists\n");
7955 LOGD("new active pad name: %s\n", change_pad_name);
7957 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
7958 if (sinkpad == NULL) {
7959 LOGD("sinkpad is NULL");
7960 result = MM_ERROR_PLAYER_INTERNAL;
7964 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
7965 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
7967 caps = gst_pad_get_current_caps(sinkpad);
7968 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
7971 gst_object_unref(sinkpad);
7973 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
7974 __mmplayer_set_audio_attrs(player, caps);
7978 MMPLAYER_FREEIF(change_pad_name);
7982 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
7984 int result = MM_ERROR_NONE;
7985 mm_player_t* player = NULL;
7986 MMPlayerGstElement* mainbin = NULL;
7988 gint current_active_index = 0;
7990 GstState current_state = GST_STATE_VOID_PENDING;
7991 GstEvent* event = NULL;
7996 player = (mm_player_t*)hplayer;
7997 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7999 if (!player->pipeline) {
8000 LOGE("Track %d pre setting -> %d\n", type, index);
8002 player->selector[type].active_pad_index = index;
8006 mainbin = player->pipeline->mainbin;
8008 current_active_index = player->selector[type].active_pad_index;
8010 /*If index is same as running index no need to change the pad*/
8011 if (current_active_index == index)
8014 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8015 result = MM_ERROR_PLAYER_INVALID_STATE;
8019 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8020 if (current_state < GST_STATE_PAUSED) {
8021 result = MM_ERROR_PLAYER_INVALID_STATE;
8022 LOGW("Pipeline not in porper state\n");
8026 result = __mmplayer_change_selector_pad(player, type, index);
8027 if (result != MM_ERROR_NONE) {
8028 LOGE("change selector pad error\n");
8032 player->selector[type].active_pad_index = index;
8034 if (current_state == GST_STATE_PLAYING) {
8035 event = gst_event_new_seek(player->playback_rate, 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);
8037 __mmplayer_gst_send_event_to_sink(player, event);
8039 result = MM_ERROR_PLAYER_INTERNAL;
8048 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
8050 mm_player_t* player = (mm_player_t*) hplayer;
8054 /* check player handle */
8055 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8057 *silent = player->set_mode.subtitle_off;
8059 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
8063 return MM_ERROR_NONE;
8067 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8069 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8070 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8072 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8073 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8077 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8078 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8079 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8080 mm_player_dump_t *dump_s;
8081 dump_s = g_malloc(sizeof(mm_player_dump_t));
8083 if (dump_s == NULL) {
8084 LOGE("malloc fail");
8088 dump_s->dump_element_file = NULL;
8089 dump_s->dump_pad = NULL;
8090 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8092 if (dump_s->dump_pad) {
8093 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
8094 snprintf(dump_file_name, PLAYER_INI_MAX_STRLEN*2, "%s/%s_sink_pad.dump", player->ini.dump_element_path, player->ini.dump_element_keyword[idx]);
8095 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8096 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);
8097 /* add list for removed buffer probe and close FILE */
8098 player->dump_list = g_list_append(player->dump_list, dump_s);
8099 LOGD("%s sink pad added buffer probe for dump", factory_name);
8104 LOGE("failed to get %s sink pad added", factory_name);
8111 static GstPadProbeReturn
8112 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8114 FILE *dump_data = (FILE *) u_data;
8116 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8117 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8119 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
8121 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8123 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8125 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8127 return GST_PAD_PROBE_OK;
8131 __mmplayer_release_dump_list(GList *dump_list)
8134 GList *d_list = dump_list;
8135 for (; d_list; d_list = g_list_next(d_list)) {
8136 mm_player_dump_t *dump_s = d_list->data;
8137 if (dump_s->dump_pad) {
8138 if (dump_s->probe_handle_id)
8139 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8141 if (dump_s->dump_element_file) {
8142 fclose(dump_s->dump_element_file);
8143 dump_s->dump_element_file = NULL;
8145 MMPLAYER_FREEIF(dump_s);
8147 g_list_free(dump_list);
8153 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
8155 mm_player_t* player = (mm_player_t*) hplayer;
8159 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8160 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8162 *exist = player->has_closed_caption;
8166 return MM_ERROR_NONE;
8169 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
8173 // LOGD("unref internal gst buffer %p", buffer);
8174 gst_buffer_unref((GstBuffer *)buffer);
8180 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8182 mm_player_t *player = (mm_player_t *) hplayer;
8186 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8187 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8189 if (MMPLAYER_IS_STREAMING(player))
8190 *timeout = player->ini.live_state_change_timeout;
8192 *timeout = player->ini.localplayback_state_change_timeout;
8194 LOGD("timeout = %d", *timeout);
8197 return MM_ERROR_NONE;
8200 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8202 mm_player_t* player = (mm_player_t*) hplayer;
8206 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8207 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8209 *num = player->video_num_buffers;
8210 *extra_num = player->video_extra_num_buffers;
8212 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8215 return MM_ERROR_NONE;
8219 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
8223 MMPLAYER_RETURN_IF_FAIL(player);
8225 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8227 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8228 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8229 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8230 player->storage_info[i].id = -1;
8231 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8233 if (path_type != MMPLAYER_PATH_MAX)
8241 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8243 int ret = MM_ERROR_NONE;
8244 mm_player_t* player = (mm_player_t*)hplayer;
8245 MMMessageParamType msg_param = {0, };
8248 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8250 LOGW("state changed storage %d:%d", id, state);
8252 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8253 return MM_ERROR_NONE;
8255 /* FIXME: text path should be handled seperately. */
8256 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8257 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8258 LOGW("external storage is removed");
8260 if (player->msg_posted == FALSE) {
8261 memset(&msg_param, 0, sizeof(MMMessageParamType));
8262 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8263 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8264 player->msg_posted = TRUE;
8267 /* unrealize the player */
8268 ret = _mmplayer_unrealize(hplayer);
8269 if (ret != MM_ERROR_NONE)
8270 LOGE("failed to unrealize");
8277 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8279 int ret = MM_ERROR_NONE;
8280 mm_player_t* player = (mm_player_t*) hplayer;
8281 int idx = 0, total = 0;
8282 gchar *result = NULL, *tmp = NULL;
8285 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8286 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8288 total = *num = g_list_length(player->adaptive_info.var_list);
8290 LOGW("There is no stream variant info.");
8294 result = g_strdup("");
8295 for (idx = 0 ; idx < total ; idx++) {
8296 VariantData *v_data = NULL;
8297 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8300 gchar data[64] = {0};
8301 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8303 tmp = g_strconcat(result, data, NULL);
8307 LOGW("There is no variant data in %d", idx);
8312 *var_info = (char *)result;
8314 LOGD("variant info %d:%s", *num, *var_info);
8319 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8321 int ret = MM_ERROR_NONE;
8322 mm_player_t* player = (mm_player_t*) hplayer;
8325 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8327 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8329 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8330 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8331 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8333 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8334 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8335 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8336 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8338 /* FIXME: seek to current position for applying new variant limitation */
8346 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8348 int ret = MM_ERROR_NONE;
8349 mm_player_t* player = (mm_player_t*) hplayer;
8352 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8353 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8355 *bandwidth = player->adaptive_info.limit.bandwidth;
8356 *width = player->adaptive_info.limit.width;
8357 *height = player->adaptive_info.limit.height;
8359 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8365 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
8367 int ret = MM_ERROR_NONE;
8368 mm_player_t* player = (mm_player_t*) hplayer;
8371 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8373 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
8374 LOGW("buffer_ms will not be applied.");
8376 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
8378 if (player->streamer == NULL) {
8379 player->streamer = __mm_player_streaming_create();
8380 __mm_player_streaming_initialize(player->streamer);
8384 player->streamer->buffering_req.prebuffer_time = buffer_ms;
8386 if (rebuffer_ms >= 0)
8387 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
8394 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
8396 int ret = MM_ERROR_NONE;
8397 mm_player_t* player = (mm_player_t*) hplayer;
8400 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8401 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8403 if (player->streamer == NULL) {
8404 player->streamer = __mm_player_streaming_create();
8405 __mm_player_streaming_initialize(player->streamer);
8408 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
8409 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8411 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
8417 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8419 #define IDX_FIRST_SW_CODEC 0
8420 mm_player_t* player = (mm_player_t*) hplayer;
8421 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8422 MMHandleType attrs = 0;
8425 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8427 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8428 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8429 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8431 switch (stream_type) {
8432 case MM_PLAYER_STREAM_TYPE_AUDIO:
8433 /* to support audio codec selection, codec info have to be added in ini file as below.
8434 audio codec element hw = xxxx
8435 audio codec element sw = avdec */
8436 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8437 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8438 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8439 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8440 LOGE("There is no audio codec info for codec_type %d", codec_type);
8441 return MM_ERROR_PLAYER_NO_OP;
8444 case MM_PLAYER_STREAM_TYPE_VIDEO:
8445 /* to support video codec selection, codec info have to be added in ini file as below.
8446 video codec element hw = omx
8447 video codec element sw = avdec */
8448 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8449 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8450 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8451 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8452 LOGE("There is no video codec info for codec_type %d", codec_type);
8453 return MM_ERROR_PLAYER_NO_OP;
8457 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8458 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8462 LOGD("update %s codec_type to %d", attr_name, codec_type);
8464 attrs = MMPLAYER_GET_ATTRS(player);
8465 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8467 if (mm_attrs_commit_all(player->attrs)) {
8468 LOGE("failed to commit codec_type attributes");
8469 return MM_ERROR_PLAYER_INTERNAL;
8473 return MM_ERROR_NONE;
8477 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8479 mm_player_t* player = (mm_player_t*) hplayer;
8480 GstElement* rg_vol_element = NULL;
8484 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8486 player->sound.rg_enable = enabled;
8488 /* just hold rgvolume enable value if pipeline is not ready */
8489 if (!player->pipeline || !player->pipeline->audiobin) {
8490 LOGD("pipeline is not ready. holding rgvolume enable value\n");
8491 return MM_ERROR_NONE;
8494 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8496 if (!rg_vol_element) {
8497 LOGD("rgvolume element is not created");
8498 return MM_ERROR_PLAYER_INTERNAL;
8502 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8504 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8508 return MM_ERROR_NONE;
8512 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8514 mm_player_t* player = (mm_player_t*) hplayer;
8515 GstElement* rg_vol_element = NULL;
8516 gboolean enable = FALSE;
8520 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8521 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8523 /* just hold enable_rg value if pipeline is not ready */
8524 if (!player->pipeline || !player->pipeline->audiobin) {
8525 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
8526 *enabled = player->sound.rg_enable;
8527 return MM_ERROR_NONE;
8530 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8532 if (!rg_vol_element) {
8533 LOGD("rgvolume element is not created");
8534 return MM_ERROR_PLAYER_INTERNAL;
8537 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8542 return MM_ERROR_NONE;
8546 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8548 mm_player_t* player = (mm_player_t*) hplayer;
8549 MMHandleType attrs = 0;
8550 void *handle = NULL;
8551 int ret = MM_ERROR_NONE;
8555 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8557 attrs = MMPLAYER_GET_ATTRS(player);
8558 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8560 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8562 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8563 return MM_ERROR_PLAYER_INTERNAL;
8566 player->video_roi.scale_x = scale_x;
8567 player->video_roi.scale_y = scale_y;
8568 player->video_roi.scale_width = scale_width;
8569 player->video_roi.scale_height = scale_height;
8571 /* check video sinkbin is created */
8572 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8573 return MM_ERROR_NONE;
8575 if (!gst_video_overlay_set_video_roi_area(
8576 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8577 scale_x, scale_y, scale_width, scale_height))
8578 ret = MM_ERROR_PLAYER_INTERNAL;
8580 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8581 scale_x, scale_y, scale_width, scale_height);
8589 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8591 mm_player_t* player = (mm_player_t*) hplayer;
8592 int ret = MM_ERROR_NONE;
8596 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8597 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8599 *scale_x = player->video_roi.scale_x;
8600 *scale_y = player->video_roi.scale_y;
8601 *scale_width = player->video_roi.scale_width;
8602 *scale_height = player->video_roi.scale_height;
8604 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8605 *scale_x, *scale_y, *scale_width, *scale_height);
8611 __mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs)
8613 gboolean ret = FALSE;
8614 gint64 dur_nsec = 0;
8615 LOGD("try to update duration");
8617 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8618 player->duration = dur_nsec;
8619 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8623 if (player->duration < 0) {
8624 LOGW("duration is Non-Initialized !!!");
8625 player->duration = 0;
8628 /* update streaming service type */
8629 player->streaming_type = __mmplayer_get_stream_service_type(player);
8631 /* check duration is OK */
8632 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
8633 /* FIXIT : find another way to get duration here. */
8634 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8641 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8643 /* update audio params
8644 NOTE : We need original audio params and it can be only obtained from src pad of audio
8645 decoder. Below code only valid when we are not using 'resampler' just before
8646 'audioconverter'. */
8647 GstCaps *caps_a = NULL;
8649 gint samplerate = 0, channels = 0;
8650 GstStructure* p = NULL;
8652 LOGD("try to update audio attrs");
8654 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8655 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8657 pad = gst_element_get_static_pad(
8658 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8661 LOGW("failed to get pad from audiosink");
8665 caps_a = gst_pad_get_current_caps(pad);
8668 LOGW("not ready to get audio caps");
8669 gst_object_unref(pad);
8673 p = gst_caps_get_structure(caps_a, 0);
8675 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8677 gst_structure_get_int(p, "rate", &samplerate);
8678 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8680 gst_structure_get_int(p, "channels", &channels);
8681 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8683 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8685 gst_caps_unref(caps_a);
8686 gst_object_unref(pad);
8692 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8694 LOGD("try to update video attrs");
8696 GstCaps *caps_v = NULL;
8700 GstStructure* p = NULL;
8702 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8703 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8705 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8707 LOGD("no videosink sink pad");
8711 caps_v = gst_pad_get_current_caps(pad);
8712 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8713 if (!caps_v && player->v_stream_caps) {
8714 caps_v = player->v_stream_caps;
8715 gst_caps_ref(caps_v);
8719 LOGD("no negitiated caps from videosink");
8720 gst_object_unref(pad);
8724 p = gst_caps_get_structure(caps_v, 0);
8725 gst_structure_get_int(p, "width", &width);
8726 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8728 gst_structure_get_int(p, "height", &height);
8729 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8731 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8733 SECURE_LOGD("width : %d height : %d", width, height);
8735 gst_caps_unref(caps_v);
8736 gst_object_unref(pad);
8739 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8740 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8747 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8749 gboolean ret = FALSE;
8750 guint64 data_size = 0;
8754 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8755 if (!player->duration)
8758 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8759 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8760 if (stat(path, &sb) == 0)
8761 data_size = (guint64)sb.st_size;
8763 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8764 data_size = player->http_content_size;
8767 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8770 guint64 bitrate = 0;
8771 guint64 msec_dur = 0;
8773 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8775 bitrate = data_size * 8 * 1000 / msec_dur;
8776 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8777 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8781 LOGD("player duration is less than 0");
8785 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8786 if (player->total_bitrate) {
8787 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
8795 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile* data, const char *uri, int uri_type)
8797 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8798 data->uri_type = uri_type;
8801 __mmplayer_set_mem_uri(MMPlayerParseProfile* data, char *path, void *param)
8803 int ret = MM_ERROR_PLAYER_INVALID_URI;
8805 char *buffer = NULL;
8806 char *seperator = strchr(path, ',');
8807 char ext[100] = {0,}, size[100] = {0,};
8810 if ((buffer = strstr(path, "ext="))) {
8811 buffer += strlen("ext=");
8813 if (strlen(buffer)) {
8814 strncpy(ext, buffer, 99);
8816 if ((seperator = strchr(ext, ','))
8817 || (seperator = strchr(ext, ' '))
8818 || (seperator = strchr(ext, '\0'))) {
8819 seperator[0] = '\0';
8824 if ((buffer = strstr(path, "size="))) {
8825 buffer += strlen("size=");
8827 if (strlen(buffer) > 0) {
8828 strncpy(size, buffer, 99);
8830 if ((seperator = strchr(size, ','))
8831 || (seperator = strchr(size, ' '))
8832 || (seperator = strchr(size, '\0'))) {
8833 seperator[0] = '\0';
8836 mem_size = atoi(size);
8841 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8843 if (mem_size && param) {
8844 if (data->input_mem.buf)
8845 free(data->input_mem.buf);
8846 data->input_mem.buf = malloc(mem_size);
8848 if (data->input_mem.buf) {
8849 memcpy(data->input_mem.buf, param, mem_size);
8850 data->input_mem.len = mem_size;
8851 ret = MM_ERROR_NONE;
8853 LOGE("failed to alloc mem %d", mem_size);
8854 ret = MM_ERROR_PLAYER_INTERNAL;
8857 data->input_mem.offset = 0;
8858 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8865 __mmplayer_set_file_uri(MMPlayerParseProfile* data, const char *uri)
8867 gchar *location = NULL;
8870 int ret = MM_ERROR_NONE;
8872 if ((path = strstr(uri, "file://"))) {
8873 location = g_filename_from_uri(uri, NULL, &err);
8874 if (!location || (err != NULL)) {
8875 LOGE("Invalid URI '%s' for filesrc: %s", path,
8876 (err != NULL) ? err->message : "unknown error");
8882 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8883 return MM_ERROR_PLAYER_INVALID_URI;
8885 LOGD("path from uri: %s", location);
8888 path = (location != NULL) ? (location) : ((char *)uri);
8891 ret = util_exist_file_path(path);
8893 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8894 if (ret == MM_ERROR_NONE) {
8895 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8896 if (util_is_sdp_file(path)) {
8897 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8898 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8900 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8902 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8903 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8905 LOGE("invalid uri, could not play..\n");
8906 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8915 static MMPlayerVideoStreamDataType*
8916 __mmplayer_create_stream_from_pad(GstPad *pad)
8918 GstCaps *caps = NULL;
8919 GstStructure *structure = NULL;
8920 unsigned int fourcc = 0;
8921 const gchar *string_format = NULL;
8922 MMPlayerVideoStreamDataType *stream = NULL;
8924 MMPixelFormatType format;
8926 caps = gst_pad_get_current_caps(pad);
8928 LOGE("Caps is NULL.");
8932 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
8933 structure = gst_caps_get_structure(caps, 0);
8934 gst_structure_get_int(structure, "width", &width);
8935 gst_structure_get_int(structure, "height", &height);
8936 string_format = gst_structure_get_string(structure, "format");
8938 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
8939 format = util_get_pixtype(fourcc);
8940 gst_caps_unref(caps);
8943 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
8944 LOGE("Wrong condition!!");
8948 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
8950 LOGE("failed to alloc mem for video data");
8954 stream->width = width;
8955 stream->height = height;
8956 stream->format = format;
8962 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
8964 unsigned int pitch = 0;
8966 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
8968 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
8969 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
8970 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
8971 stream->stride[index] = pitch;
8972 stream->elevation[index] = stream->height;
8977 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
8979 if (stream->format == MM_PIXEL_FORMAT_I420) {
8980 int ret = TBM_SURFACE_ERROR_NONE;
8981 tbm_surface_h surface;
8982 tbm_surface_info_s info;
8984 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
8986 ret = tbm_surface_get_info(surface, &info);
8987 if (ret != TBM_SURFACE_ERROR_NONE) {
8988 tbm_surface_destroy(surface);
8992 tbm_surface_destroy(surface);
8993 stream->stride[0] = info.planes[0].stride;
8994 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
8995 stream->stride[1] = info.planes[1].stride;
8996 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
8997 stream->stride[2] = info.planes[2].stride;
8998 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
8999 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9000 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9001 stream->stride[0] = stream->width * 4;
9002 stream->elevation[0] = stream->height;
9003 stream->bo_size = stream->stride[0] * stream->height;
9005 LOGE("Not support format %d", stream->format);
9013 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9015 tbm_bo_handle thandle;
9017 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9018 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9019 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9023 unsigned char *src = NULL;
9024 unsigned char *dest = NULL;
9025 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9027 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9029 LOGE("fail to gst_memory_map");
9033 if (!mapinfo.data) {
9034 LOGE("data pointer is wrong");
9038 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9039 if (!stream->bo[0]) {
9040 LOGE("Fail to tbm_bo_alloc!!");
9044 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9046 LOGE("thandle pointer is wrong");
9050 if (stream->format == MM_PIXEL_FORMAT_I420) {
9051 src_stride[0] = GST_ROUND_UP_4(stream->width);
9052 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9053 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9054 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9057 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9058 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9060 for (i = 0; i < 3; i++) {
9061 src = mapinfo.data + src_offset[i];
9062 dest = thandle.ptr + dest_offset[i];
9067 for (j = 0; j < stream->height >> k; j++) {
9068 memcpy(dest, src, stream->width>>k);
9069 src += src_stride[i];
9070 dest += stream->stride[i];
9073 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9074 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9076 LOGE("Not support format %d", stream->format);
9080 tbm_bo_unmap(stream->bo[0]);
9081 gst_memory_unmap(mem, &mapinfo);
9087 tbm_bo_unmap(stream->bo[0]);
9090 gst_memory_unmap(mem, &mapinfo);
9096 __mmplayer_set_pause_state(mm_player_t *player)
9098 if (player->sent_bos)
9101 /* rtsp case, get content attrs by GstMessage */
9102 if (MMPLAYER_IS_RTSP_STREAMING(player))
9105 /* it's first time to update all content attrs. */
9106 __mmplayer_update_content_attrs(player, ATTR_ALL);
9110 __mmplayer_set_playing_state(mm_player_t *player)
9112 gchar *audio_codec = NULL;
9114 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9115 /* initialize because auto resume is done well. */
9116 player->resumed_by_rewind = FALSE;
9117 player->playback_rate = 1.0;
9120 if (player->sent_bos)
9123 /* try to get content metadata */
9125 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9126 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9127 * legacy mmfw-player api
9129 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9131 if ((player->cmd == MMPLAYER_COMMAND_START)
9132 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9133 __mmplayer_handle_missed_plugin(player);
9136 /* check audio codec field is set or not
9137 * we can get it from typefinder or codec's caps.
9139 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9141 /* The codec format can't be sent for audio only case like amr, mid etc.
9142 * Because, parser don't make related TAG.
9143 * So, if it's not set yet, fill it with found data.
9146 if (g_strrstr(player->type, "audio/midi"))
9147 audio_codec = "MIDI";
9148 else if (g_strrstr(player->type, "audio/x-amr"))
9149 audio_codec = "AMR";
9150 else if (g_strrstr(player->type, "audio/mpeg")
9151 && !g_strrstr(player->type, "mpegversion= (int)1"))
9152 audio_codec = "AAC";
9154 audio_codec = "unknown";
9156 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9158 if (mm_attrs_commit_all(player->attrs))
9159 LOGE("failed to update attributes\n");
9161 LOGD("set audio codec type with caps\n");