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 1.0, /* low percent */
1369 player->ini.http_buffering_limit, /* high percent */
1370 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1372 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1379 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1381 mm_player_t *player = NULL;
1382 GstElement *video_selector = NULL;
1383 GstElement *audio_selector = NULL;
1384 GstElement *text_selector = NULL;
1387 player = (mm_player_t*) data;
1389 LOGD("no-more-pad signal handling");
1391 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1392 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1393 LOGW("player is shutting down");
1397 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1398 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1399 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1400 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1401 LOGE("failed to set queue2 buffering");
1406 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1407 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1408 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1410 /* create video path followed by video-select */
1411 if (video_selector && !audio_selector && !text_selector)
1412 player->no_more_pad = TRUE;
1414 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1417 /* create audio path followed by audio-select */
1418 if (audio_selector && !text_selector)
1419 player->no_more_pad = TRUE;
1421 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1425 /* create text path followed by text-select */
1426 __mmplayer_create_text_sink_path(player, text_selector);
1429 if (player->gapless.reconfigure) {
1430 player->gapless.reconfigure = FALSE;
1431 MMPLAYER_PLAYBACK_UNLOCK(player);
1438 __mmplayer_gst_add_sinkbin_to_pipeline(mm_player_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1440 gboolean ret = FALSE;
1441 GstElement *pipeline = NULL;
1442 GstPad *sinkpad = NULL;
1445 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1446 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1448 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1450 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1452 LOGE("failed to get pad from sinkbin");
1458 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1459 LOGE("failed to link sinkbin for reusing");
1460 goto EXIT; /* exit either pass or fail */
1464 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1465 LOGE("failed to set state(READY) to sinkbin");
1470 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1471 LOGE("failed to add sinkbin to pipeline");
1476 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1477 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1482 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1483 LOGE("failed to set state(PAUSED) to sinkbin");
1492 gst_object_unref(GST_OBJECT(sinkpad));
1499 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1501 mm_player_t *player = NULL;
1502 MMHandleType attrs = 0;
1503 GstCaps *caps = NULL;
1504 gchar *caps_str = NULL;
1505 GstStructure *str = NULL;
1506 const gchar *name = NULL;
1507 GstElement *sinkbin = NULL;
1508 gboolean reusing = FALSE;
1509 gboolean caps_ret = TRUE;
1510 gchar *sink_pad_name = "sink";
1513 player = (mm_player_t*) data;
1516 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1517 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1519 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1523 caps_str = gst_caps_to_string(caps);
1525 /* LOGD("detected mimetype : %s", name); */
1526 if (strstr(name, "audio")) {
1527 if (player->pipeline->audiobin == NULL) {
1528 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1529 LOGE("failed to create audiobin. continuing without audio");
1533 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1534 LOGD("creating audiobin success");
1537 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1538 LOGD("reusing audiobin");
1539 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
1541 } else if (strstr(name, "video")) {
1542 /* 1. zero copy is updated at _decode_pad_added()
1543 * 2. NULL surface type is handled in _decode_pad_added() */
1544 LOGD("zero copy %d", player->set_mode.video_zc);
1545 if (player->pipeline->videobin == NULL) {
1546 int surface_type = 0;
1547 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1548 LOGD("display_surface_type (%d)", surface_type);
1550 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) {
1551 LOGD("mark video overlay for acquire");
1552 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1553 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1554 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1555 &player->video_overlay_resource)
1556 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1557 LOGE("could not mark video_overlay resource for acquire");
1562 player->interrupted_by_resource = FALSE;
1564 if (mm_resource_manager_commit(player->resource_manager) !=
1565 MM_RESOURCE_MANAGER_ERROR_NONE) {
1566 LOGE("could not acquire resources for video playing");
1570 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1571 LOGE("failed to create videobin. continuing without video");
1575 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1576 LOGD("creating videosink bin success");
1579 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1580 LOGD("re-using videobin");
1581 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
1583 } else if (strstr(name, "text")) {
1584 if (player->pipeline->textbin == NULL) {
1585 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1586 LOGE("failed to create text sink bin. continuing without text");
1590 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1591 player->textsink_linked = 1;
1592 LOGD("creating textsink bin success");
1594 if (!player->textsink_linked) {
1595 LOGD("re-using textbin");
1597 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1598 player->textsink_linked = 1;
1600 /* linked textbin exist which means that the external subtitle path exist already */
1601 LOGW("ignoring internal subtutle since external subtitle is available");
1604 sink_pad_name = "text_sink";
1606 LOGW("unknown mime type %s, ignoring it", name);
1610 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1613 LOGD("[handle: %p] success to create and link sink bin", player);
1615 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1616 * streaming task. if the task blocked, then buffer will not flow to the next element
1617 *(autoplugging element). so this is special hack for streaming. please try to remove it
1619 /* dec stream count. we can remove fakesink if it's zero */
1620 if (player->num_dynamic_pad)
1621 player->num_dynamic_pad--;
1623 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1625 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1626 __mmplayer_pipeline_complete(NULL, player);
1630 MMPLAYER_FREEIF(caps_str);
1633 gst_caps_unref(caps);
1635 /* flusing out new attributes */
1636 if (mm_attrs_commit_all(attrs))
1637 LOGE("failed to comit attributes");
1643 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int display_angle, int orientation, int *value)
1645 int required_angle = 0; /* Angle required for straight view */
1646 int rotation_angle = 0;
1648 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1649 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1651 /* Counter clockwise */
1652 switch (orientation) {
1657 required_angle = 270;
1660 required_angle = 180;
1663 required_angle = 90;
1667 rotation_angle = display_angle + required_angle;
1668 if (rotation_angle >= 360)
1669 rotation_angle -= 360;
1671 /* chech if supported or not */
1672 if (rotation_angle % 90) {
1673 LOGD("not supported rotation angle = %d", rotation_angle);
1677 switch (rotation_angle) {
1679 *value = MM_DISPLAY_ROTATION_NONE;
1682 *value = MM_DISPLAY_ROTATION_90;
1685 *value = MM_DISPLAY_ROTATION_180;
1688 *value = MM_DISPLAY_ROTATION_270;
1692 LOGD("setting rotation property value : %d", *value);
1698 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
1700 /* check video sinkbin is created */
1701 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1703 player->pipeline->videobin &&
1704 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1705 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1706 MM_ERROR_PLAYER_NOT_INITIALIZED);
1708 return MM_ERROR_NONE;
1712 __mmplayer_get_video_angle(mm_player_t* player, int *display_angle, int *orientation)
1714 int display_rotation = 0;
1715 gchar *org_orient = NULL;
1716 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1719 LOGE("cannot get content attribute");
1720 return MM_ERROR_PLAYER_INTERNAL;
1723 if (display_angle) {
1724 /* update user roation */
1725 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1727 /* Counter clockwise */
1728 switch (display_rotation) {
1729 case MM_DISPLAY_ROTATION_NONE:
1732 case MM_DISPLAY_ROTATION_90:
1733 *display_angle = 90;
1735 case MM_DISPLAY_ROTATION_180:
1736 *display_angle = 180;
1738 case MM_DISPLAY_ROTATION_270:
1739 *display_angle = 270;
1742 LOGW("wrong angle type : %d", display_rotation);
1745 LOGD("check user angle: %d", *display_angle);
1749 /* Counter clockwise */
1750 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1753 if (!strcmp(org_orient, "rotate-90"))
1755 else if (!strcmp(org_orient, "rotate-180"))
1757 else if (!strcmp(org_orient, "rotate-270"))
1760 LOGD("original rotation is %s", org_orient);
1762 LOGD("content_video_orientation get fail");
1765 LOGD("check orientation: %d", *orientation);
1768 return MM_ERROR_NONE;
1772 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
1774 int rotation_value = 0;
1775 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1776 int display_angle = 0;
1779 /* check video sinkbin is created */
1780 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1783 __mmplayer_get_video_angle(player, &display_angle, &orientations);
1785 /* get rotation value to set */
1786 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1787 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1788 LOGD("set video param : rotate %d", rotation_value);
1792 __mmplayer_video_param_set_display_visible(mm_player_t* player)
1794 MMHandleType attrs = 0;
1798 /* check video sinkbin is created */
1799 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1802 attrs = MMPLAYER_GET_ATTRS(player);
1803 MMPLAYER_RETURN_IF_FAIL(attrs);
1805 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1806 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1807 LOGD("set video param : visible %d", visible);
1811 __mmplayer_video_param_set_display_method(mm_player_t* player)
1813 MMHandleType attrs = 0;
1814 int display_method = 0;
1817 /* check video sinkbin is created */
1818 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1821 attrs = MMPLAYER_GET_ATTRS(player);
1822 MMPLAYER_RETURN_IF_FAIL(attrs);
1824 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1825 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1826 LOGD("set video param : method %d", display_method);
1829 __mmplayer_video_param_set_video_roi_area(mm_player_t* player)
1831 MMHandleType attrs = 0;
1832 void *handle = NULL;
1835 /* check video sinkbin is created */
1836 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1837 LOGW("There is no video sink");
1841 attrs = MMPLAYER_GET_ATTRS(player);
1842 MMPLAYER_RETURN_IF_FAIL(attrs);
1843 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1845 gst_video_overlay_set_video_roi_area(
1846 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1847 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1848 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1849 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1854 __mmplayer_video_param_set_roi_area(mm_player_t* player)
1856 MMHandleType attrs = 0;
1857 void *handle = NULL;
1861 int win_roi_width = 0;
1862 int win_roi_height = 0;
1865 /* check video sinkbin is created */
1866 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1867 LOGW("There is no video sink");
1871 attrs = MMPLAYER_GET_ATTRS(player);
1872 MMPLAYER_RETURN_IF_FAIL(attrs);
1874 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1877 /* It should be set after setting window */
1878 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1879 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1880 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1881 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1883 /* After setting window handle, set display roi area */
1884 gst_video_overlay_set_display_roi_area(
1885 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1886 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1887 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1888 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1892 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
1894 MMHandleType attrs = 0;
1895 void *handle = NULL;
1897 /* check video sinkbin is created */
1898 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1901 attrs = MMPLAYER_GET_ATTRS(player);
1902 MMPLAYER_RETURN_IF_FAIL(attrs);
1904 /* common case if using overlay surface */
1905 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1908 /* default is using wl_surface_id */
1909 unsigned int wl_surface_id = 0;
1910 wl_surface_id = *(int*)handle;
1911 LOGD("set video param : wl_surface_id %d", wl_surface_id);
1912 gst_video_overlay_set_wl_window_wl_surface_id(
1913 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1916 /* FIXIT : is it error case? */
1917 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1922 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
1924 bool update_all_param = FALSE;
1927 /* check video sinkbin is created */
1928 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1929 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1931 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1932 LOGE("can not find tizenwlsink");
1933 return MM_ERROR_PLAYER_INTERNAL;
1936 LOGD("param_name : %s", param_name);
1937 if (!g_strcmp0(param_name, "update_all_param"))
1938 update_all_param = TRUE;
1940 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1941 __mmplayer_video_param_set_display_overlay(player);
1942 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1943 __mmplayer_video_param_set_display_method(player);
1944 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1945 __mmplayer_video_param_set_display_visible(player);
1946 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1947 __mmplayer_video_param_set_display_rotation(player);
1948 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
1949 __mmplayer_video_param_set_roi_area(player);
1950 if (update_all_param)
1951 __mmplayer_video_param_set_video_roi_area(player);
1953 return MM_ERROR_NONE;
1957 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
1959 MMHandleType attrs = 0;
1960 int surface_type = 0;
1961 int ret = MM_ERROR_NONE;
1965 /* check video sinkbin is created */
1966 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1967 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1969 attrs = MMPLAYER_GET_ATTRS(player);
1971 LOGE("cannot get content attribute");
1972 return MM_ERROR_PLAYER_INTERNAL;
1974 LOGD("param_name : %s", param_name);
1976 /* update display surface */
1977 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
1978 LOGD("check display surface type attribute: %d", surface_type);
1980 /* configuring display */
1981 switch (surface_type) {
1982 case MM_DISPLAY_SURFACE_OVERLAY:
1984 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
1985 if (ret != MM_ERROR_NONE)
1993 return MM_ERROR_NONE;
1997 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
1999 gboolean disable_overlay = FALSE;
2000 mm_player_t* player = (mm_player_t*) hplayer;
2001 int ret = MM_ERROR_NONE;
2004 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2005 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2006 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2007 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2009 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2010 LOGW("Display control is not supported");
2011 return MM_ERROR_PLAYER_INTERNAL;
2014 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2016 if (audio_only == (bool)disable_overlay) {
2017 LOGE("It's the same with current setting: (%d)", audio_only);
2018 return MM_ERROR_NONE;
2022 LOGE("disable overlay");
2023 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2025 /* release overlay resource */
2026 if (player->video_overlay_resource != NULL) {
2027 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2028 player->video_overlay_resource);
2029 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2030 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
2033 player->video_overlay_resource = NULL;
2036 ret = mm_resource_manager_commit(player->resource_manager);
2037 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2038 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
2042 /* mark video overlay for acquire */
2043 if (player->video_overlay_resource == NULL) {
2044 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2045 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2046 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2047 &player->video_overlay_resource);
2048 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2049 LOGE("could not prepare for video_overlay resource\n");
2054 player->interrupted_by_resource = FALSE;
2055 /* acquire resources for video overlay */
2056 ret = mm_resource_manager_commit(player->resource_manager);
2057 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2058 LOGE("could not acquire resources for video playing\n");
2062 LOGD("enable overlay");
2063 __mmplayer_video_param_set_display_overlay(player);
2064 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2069 return MM_ERROR_NONE;
2073 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2075 mm_player_t* player = (mm_player_t*) hplayer;
2076 gboolean disable_overlay = FALSE;
2080 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2081 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2082 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2083 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2084 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2086 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2087 LOGW("Display control is not supported");
2088 return MM_ERROR_PLAYER_INTERNAL;
2091 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2093 *paudio_only = (bool)(disable_overlay);
2095 LOGD("audio_only : %d", *paudio_only);
2099 return MM_ERROR_NONE;
2103 __mmplayer_gst_element_link_bucket(GList* element_bucket)
2105 GList* bucket = element_bucket;
2106 MMPlayerGstElement* element = NULL;
2107 MMPlayerGstElement* prv_element = NULL;
2108 gint successful_link_count = 0;
2112 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2114 prv_element = (MMPlayerGstElement*)bucket->data;
2115 bucket = bucket->next;
2117 for (; bucket; bucket = bucket->next) {
2118 element = (MMPlayerGstElement*)bucket->data;
2120 if (element && element->gst) {
2121 if (prv_element && prv_element->gst) {
2122 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2123 LOGD("linking [%s] to [%s] success\n",
2124 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2125 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2126 successful_link_count++;
2128 LOGD("linking [%s] to [%s] failed\n",
2129 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2130 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2136 prv_element = element;
2141 return successful_link_count;
2145 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
2147 GList* bucket = element_bucket;
2148 MMPlayerGstElement* element = NULL;
2149 int successful_add_count = 0;
2153 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2154 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2156 for (; bucket; bucket = bucket->next) {
2157 element = (MMPlayerGstElement*)bucket->data;
2159 if (element && element->gst) {
2160 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2161 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
2162 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2163 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2166 successful_add_count++;
2172 return successful_add_count;
2175 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2177 mm_player_t *player = (mm_player_t*) data;
2178 GstCaps *caps = NULL;
2179 GstStructure *str = NULL;
2181 gboolean caps_ret = TRUE;
2185 MMPLAYER_RETURN_IF_FAIL(pad);
2186 MMPLAYER_RETURN_IF_FAIL(unused);
2187 MMPLAYER_RETURN_IF_FAIL(data);
2189 caps = gst_pad_get_current_caps(pad);
2193 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2197 LOGD("name = %s", name);
2199 if (strstr(name, "audio")) {
2200 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2202 if (player->audio_stream_changed_cb) {
2203 LOGE("call the audio stream changed cb");
2204 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2206 } else if (strstr(name, "video")) {
2207 if ((name = gst_structure_get_string(str, "format")))
2208 player->set_mode.video_zc = name[0] == 'S';
2210 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2212 if (player->video_stream_changed_cb) {
2213 LOGE("call the video stream changed cb");
2214 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2217 LOGW("invalid caps info");
2222 gst_caps_unref(caps);
2232 * This function is to create audio pipeline for playing.
2234 * @param player [in] handle of player
2236 * @return This function returns zero on success.
2238 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_sink_bin
2240 /* macro for code readability. just for sinkbin-creation functions */
2241 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2243 x_bin[x_id].id = x_id;\
2244 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2245 if (!x_bin[x_id].gst) {\
2246 LOGE("failed to create %s \n", x_factory);\
2249 if (x_player->ini.set_dump_element_flag)\
2250 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2253 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2257 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
2262 MMPLAYER_RETURN_IF_FAIL(player);
2264 if (player->audio_stream_buff_list) {
2265 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2266 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2269 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2270 __mmplayer_audio_stream_send_data(player, tmp);
2273 g_free(tmp->pcm_data);
2277 g_list_free(player->audio_stream_buff_list);
2278 player->audio_stream_buff_list = NULL;
2285 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
2287 MMPlayerAudioStreamDataType audio_stream = { 0, };
2290 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2292 audio_stream.bitrate = a_buffer->bitrate;
2293 audio_stream.channel = a_buffer->channel;
2294 audio_stream.depth = a_buffer->depth;
2295 audio_stream.is_little_endian = a_buffer->is_little_endian;
2296 audio_stream.channel_mask = a_buffer->channel_mask;
2297 audio_stream.data_size = a_buffer->data_size;
2298 audio_stream.data = a_buffer->pcm_data;
2300 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
2301 player->audio_stream_render_cb(&audio_stream, player->audio_stream_cb_user_param);
2307 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
2309 mm_player_t* player = (mm_player_t*) data;
2314 gint endianness = 0;
2315 guint64 channel_mask = 0;
2316 void *a_data = NULL;
2318 mm_player_audio_stream_buff_t *a_buffer = NULL;
2319 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2323 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2325 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2326 a_data = mapinfo.data;
2327 a_size = mapinfo.size;
2329 GstCaps *caps = gst_pad_get_current_caps(pad);
2330 GstStructure *structure = gst_caps_get_structure(caps, 0);
2332 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2333 gst_structure_get_int(structure, "rate", &rate);
2334 gst_structure_get_int(structure, "channels", &channel);
2335 gst_structure_get_int(structure, "depth", &depth);
2336 gst_structure_get_int(structure, "endianness", &endianness);
2337 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2338 gst_caps_unref(GST_CAPS(caps));
2340 /* In case of the sync is false, use buffer list. *
2341 * The num of buffer list depends on the num of audio channels */
2342 if (player->audio_stream_buff_list) {
2343 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2344 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2346 if (channel_mask == tmp->channel_mask) {
2347 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2348 if (tmp->data_size + a_size < tmp->buff_size) {
2349 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2350 tmp->data_size += a_size;
2352 /* send data to client */
2353 __mmplayer_audio_stream_send_data(player, tmp);
2355 if (a_size > tmp->buff_size) {
2356 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2357 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2358 if (tmp->pcm_data == NULL) {
2359 LOGE("failed to realloc data.");
2362 tmp->buff_size = a_size;
2364 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2365 memcpy(tmp->pcm_data, a_data, a_size);
2366 tmp->data_size = a_size;
2371 LOGE("data is empty in list.");
2377 /* create new audio stream data */
2378 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
2379 if (a_buffer == NULL) {
2380 LOGE("failed to alloc data.");
2383 a_buffer->bitrate = rate;
2384 a_buffer->channel = channel;
2385 a_buffer->depth = depth;
2386 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
2387 a_buffer->channel_mask = channel_mask;
2388 a_buffer->data_size = a_size;
2390 if (!player->audio_stream_sink_sync) {
2391 /* If sync is FALSE, use buffer list to reduce the IPC. */
2392 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2393 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
2394 if (a_buffer->pcm_data == NULL) {
2395 LOGE("failed to alloc data.");
2399 memcpy(a_buffer->pcm_data, a_data, a_size);
2400 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2401 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2403 /* If sync is TRUE, send data directly. */
2404 a_buffer->pcm_data = a_data;
2405 __mmplayer_audio_stream_send_data(player, a_buffer);
2410 gst_buffer_unmap(buffer, &mapinfo);
2415 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2417 mm_player_t* player = (mm_player_t*)data;
2418 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
2419 GstPad* sinkpad = NULL;
2420 GstElement *queue = NULL, *sink = NULL;
2423 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2425 queue = gst_element_factory_make("queue", NULL);
2426 if (queue == NULL) {
2427 LOGD("fail make queue\n");
2431 sink = gst_element_factory_make("fakesink", NULL);
2433 LOGD("fail make fakesink\n");
2437 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2439 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2440 LOGW("failed to link queue & sink\n");
2444 sinkpad = gst_element_get_static_pad(queue, "sink");
2446 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2447 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
2451 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
2453 gst_object_unref(sinkpad);
2454 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
2455 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2457 gst_element_set_state(sink, GST_STATE_PAUSED);
2458 gst_element_set_state(queue, GST_STATE_PAUSED);
2460 __mmplayer_add_signal_connection(player,
2462 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2464 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2471 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
2473 gst_object_unref(GST_OBJECT(queue));
2477 gst_object_unref(GST_OBJECT(sink));
2481 gst_object_unref(GST_OBJECT(sinkpad));
2488 void __mmplayer_gst_set_pulsesink_property(mm_player_t* player, MMHandleType attrs)
2490 #define MAX_PROPS_LEN 128
2491 gint latency_mode = 0;
2492 gchar *stream_type = NULL;
2493 gchar *latency = NULL;
2495 gchar stream_props[MAX_PROPS_LEN] = {0,};
2496 GstStructure *props = NULL;
2499 * It should be set after player creation through attribute.
2500 * But, it can not be changed during playing.
2503 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2505 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
2506 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
2509 LOGE("stream_type is null.");
2511 if (player->sound.focus_id)
2512 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
2513 stream_type, stream_id, player->sound.focus_id);
2515 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
2516 stream_type, stream_id);
2517 props = gst_structure_from_string(stream_props, NULL);
2518 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2519 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].",
2520 stream_type, stream_id, player->sound.focus_id, stream_props);
2521 gst_structure_free(props);
2524 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2526 switch (latency_mode) {
2527 case AUDIO_LATENCY_MODE_LOW:
2528 latency = g_strndup("low", 3);
2530 case AUDIO_LATENCY_MODE_MID:
2531 latency = g_strndup("mid", 3);
2533 case AUDIO_LATENCY_MODE_HIGH:
2534 latency = g_strndup("high", 4);
2538 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2542 LOGD("audiosink property - latency=%s", latency);
2549 void __mmplayer_gst_set_openalsink_property(mm_player_t* player)
2551 MMPlayerGstElement *audiobin = NULL;
2554 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2556 audiobin = player->pipeline->audiobin;
2558 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2559 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2560 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2562 if (player->video360_yaw_radians <= M_PI &&
2563 player->video360_yaw_radians >= -M_PI &&
2564 player->video360_pitch_radians <= M_PI_2 &&
2565 player->video360_pitch_radians >= -M_PI_2) {
2566 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2567 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
2568 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
2569 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2570 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2571 "source-orientation-y", player->video360_metadata.init_view_heading,
2572 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2579 __mmplayer_gst_fill_audio_bucket(mm_player_t *player, GList **bucket)
2581 MMPlayerGstElement *audiobin = NULL;
2582 MMHandleType attrs = 0;
2583 GList *element_bucket = NULL;
2584 GstCaps *acaps = NULL;
2585 GstPad *sink_pad = NULL;
2588 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2589 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2591 audiobin = player->pipeline->audiobin;
2592 attrs = MMPLAYER_GET_ATTRS(player);
2595 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2597 /* replaygain volume */
2598 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2599 if (player->sound.rg_enable)
2600 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2602 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2605 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2607 if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2608 gchar *dst_format = NULL;
2610 int dst_samplerate = 0;
2611 int dst_channels = 0;
2612 GstCaps *caps = NULL;
2613 char *caps_str = NULL;
2615 /* get conf. values */
2616 mm_attrs_multiple_get(player->attrs, NULL,
2617 "pcm_audioformat", &dst_format, &dst_len,
2618 "pcm_extraction_samplerate", &dst_samplerate,
2619 "pcm_extraction_channels", &dst_channels,
2622 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2625 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2626 caps = gst_caps_new_simple("audio/x-raw",
2627 "format", G_TYPE_STRING, dst_format,
2628 "rate", G_TYPE_INT, dst_samplerate,
2629 "channels", G_TYPE_INT, dst_channels,
2632 caps_str = gst_caps_to_string(caps);
2633 LOGD("new caps : %s", caps_str);
2635 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2638 gst_caps_unref(caps);
2639 MMPLAYER_FREEIF(caps_str);
2641 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2643 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2645 /* raw pad handling signal, audiosink will be added after getting signal */
2646 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2647 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2651 /* normal playback */
2654 /* for logical volume control */
2655 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2656 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2658 if (player->sound.mute) {
2659 LOGD("mute enabled");
2660 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2663 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2665 /* audio effect element. if audio effect is enabled */
2666 if ((strcmp(player->ini.audioeffect_element, ""))
2668 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2669 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2671 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2673 if ((!player->bypass_audio_effect)
2674 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2675 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2676 if (!_mmplayer_audio_effect_custom_apply(player))
2677 LOGI("apply audio effect(custom) setting success");
2681 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2682 && (player->set_mode.rich_audio))
2683 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2686 /* create audio sink */
2687 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2688 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2689 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2691 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2692 if (player->is_360_feature_enabled &&
2693 player->is_content_spherical &&
2695 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2696 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2697 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2699 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2701 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2703 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2704 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2705 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2706 gst_caps_unref(acaps);
2708 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2710 player->is_openal_plugin_used = TRUE;
2712 if (player->is_360_feature_enabled && player->is_content_spherical)
2713 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2714 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2717 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2718 (player->videodec_linked && player->ini.use_system_clock)) {
2719 LOGD("system clock will be used.");
2720 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2723 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2724 __mmplayer_gst_set_pulsesink_property(player, attrs);
2725 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2726 __mmplayer_gst_set_openalsink_property(player);
2729 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2730 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2732 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2733 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2734 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2735 gst_object_unref(GST_OBJECT(sink_pad));
2737 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2740 *bucket = element_bucket;
2743 return MM_ERROR_NONE;
2746 g_list_free(element_bucket);
2750 return MM_ERROR_PLAYER_INTERNAL;
2754 __mmplayer_gst_create_audio_sink_bin(mm_player_t* player)
2756 MMPlayerGstElement *first_element = NULL;
2757 MMPlayerGstElement *audiobin = NULL;
2759 GstPad *ghostpad = NULL;
2760 GList *element_bucket = NULL;
2764 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2767 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2769 LOGE("failed to allocate memory for audiobin");
2770 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2774 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2775 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2776 if (!audiobin[MMPLAYER_A_BIN].gst) {
2777 LOGE("failed to create audiobin");
2782 player->pipeline->audiobin = audiobin;
2784 /* create audio filters and audiosink */
2785 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2788 /* adding created elements to bin */
2789 LOGD("adding created elements to bin");
2790 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2793 /* linking elements in the bucket by added order. */
2794 LOGD("Linking elements in the bucket by added order.");
2795 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2798 /* get first element's sinkpad for creating ghostpad */
2799 first_element = (MMPlayerGstElement *)element_bucket->data;
2800 if (!first_element) {
2801 LOGE("failed to get first elem");
2805 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2807 LOGE("failed to get pad from first element of audiobin");
2811 ghostpad = gst_ghost_pad_new("sink", pad);
2813 LOGE("failed to create ghostpad");
2817 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2818 LOGE("failed to add ghostpad to audiobin");
2822 gst_object_unref(pad);
2824 g_list_free(element_bucket);
2827 return MM_ERROR_NONE;
2830 LOGD("ERROR : releasing audiobin");
2833 gst_object_unref(GST_OBJECT(pad));
2836 gst_object_unref(GST_OBJECT(ghostpad));
2839 g_list_free(element_bucket);
2841 /* release element which are not added to bin */
2842 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2843 /* NOTE : skip bin */
2844 if (audiobin[i].gst) {
2845 GstObject* parent = NULL;
2846 parent = gst_element_get_parent(audiobin[i].gst);
2849 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2850 audiobin[i].gst = NULL;
2852 gst_object_unref(GST_OBJECT(parent));
2856 /* release audiobin with it's childs */
2857 if (audiobin[MMPLAYER_A_BIN].gst)
2858 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2860 MMPLAYER_FREEIF(audiobin);
2862 player->pipeline->audiobin = NULL;
2864 return MM_ERROR_PLAYER_INTERNAL;
2867 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
2869 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2872 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
2874 int ret = MM_ERROR_NONE;
2876 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2877 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2879 MMPLAYER_VIDEO_BO_LOCK(player);
2881 if (player->video_bo_list) {
2882 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2883 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
2884 if (tmp && tmp->bo == bo) {
2886 LOGD("release bo %p", bo);
2887 tbm_bo_unref(tmp->bo);
2888 MMPLAYER_VIDEO_BO_UNLOCK(player);
2889 MMPLAYER_VIDEO_BO_SIGNAL(player);
2894 /* hw codec is running or the list was reset for DRC. */
2895 LOGW("there is no bo list.");
2897 MMPLAYER_VIDEO_BO_UNLOCK(player);
2899 LOGW("failed to find bo %p", bo);
2904 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
2909 MMPLAYER_RETURN_IF_FAIL(player);
2911 MMPLAYER_VIDEO_BO_LOCK(player);
2912 if (player->video_bo_list) {
2913 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2914 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2915 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
2918 tbm_bo_unref(tmp->bo);
2922 g_list_free(player->video_bo_list);
2923 player->video_bo_list = NULL;
2925 player->video_bo_size = 0;
2926 MMPLAYER_VIDEO_BO_UNLOCK(player);
2933 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
2936 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2937 gboolean ret = TRUE;
2939 /* check DRC, if it is, destroy the prev bo list to create again */
2940 if (player->video_bo_size != size) {
2941 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
2942 __mmplayer_video_stream_destroy_bo_list(player);
2943 player->video_bo_size = size;
2946 MMPLAYER_VIDEO_BO_LOCK(player);
2948 if ((!player->video_bo_list) ||
2949 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
2951 /* create bo list */
2953 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
2955 if (player->video_bo_list) {
2956 /* if bo list did not created all, try it again. */
2957 idx = g_list_length(player->video_bo_list);
2958 LOGD("bo list exist(len: %d)", idx);
2961 for (; idx < player->ini.num_of_video_bo; idx++) {
2962 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
2964 LOGE("Fail to alloc bo_info.");
2967 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
2969 LOGE("Fail to tbm_bo_alloc.");
2973 bo_info->used = FALSE;
2974 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
2977 /* update video num buffers */
2978 player->video_num_buffers = idx;
2979 if (idx == player->ini.num_of_video_bo)
2980 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
2983 MMPLAYER_VIDEO_BO_UNLOCK(player);
2987 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
2991 /* get bo from list*/
2992 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2993 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
2994 if (tmp && (tmp->used == FALSE)) {
2995 LOGD("found bo %p to use", tmp->bo);
2997 MMPLAYER_VIDEO_BO_UNLOCK(player);
2998 return tbm_bo_ref(tmp->bo);
3002 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3003 MMPLAYER_VIDEO_BO_UNLOCK(player);
3007 if (player->ini.video_bo_timeout <= 0) {
3008 MMPLAYER_VIDEO_BO_WAIT(player);
3010 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
3011 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3018 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3020 mm_player_t* player = (mm_player_t*)data;
3022 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3024 /* send prerolled pkt */
3025 player->video_stream_prerolled = FALSE;
3027 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3029 /* not to send prerolled pkt again */
3030 player->video_stream_prerolled = TRUE;
3034 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3036 mm_player_t* player = (mm_player_t*)data;
3037 MMPlayerVideoStreamDataType *stream = NULL;
3038 GstMemory *mem = NULL;
3041 MMPLAYER_RETURN_IF_FAIL(player);
3042 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3044 if (player->video_stream_prerolled) {
3045 player->video_stream_prerolled = FALSE;
3046 LOGD("skip the prerolled pkt not to send it again");
3050 /* clear stream data structure */
3051 stream = __mmplayer_create_stream_from_pad(pad);
3053 LOGE("failed to alloc stream");
3057 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3059 /* set size and timestamp */
3060 mem = gst_buffer_peek_memory(buffer, 0);
3061 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3062 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3064 /* check zero-copy */
3065 if (player->set_mode.video_zc &&
3066 player->set_mode.media_packet_video_stream &&
3067 gst_is_tizen_memory(mem)) {
3068 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3069 stream->internal_buffer = gst_buffer_ref(buffer);
3070 } else { /* sw codec */
3071 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3074 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3078 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3079 LOGE("failed to send video stream data.");
3086 LOGE("release video stream resource.");
3087 if (gst_is_tizen_memory(mem)) {
3089 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3091 tbm_bo_unref(stream->bo[i]);
3094 /* unref gst buffer */
3095 if (stream->internal_buffer)
3096 gst_buffer_unref(stream->internal_buffer);
3099 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3106 __mmplayer_gst_set_video360_property(mm_player_t *player)
3108 MMPlayerGstElement *videobin = NULL;
3111 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3113 videobin = player->pipeline->videobin;
3115 /* Set spatial media metadata and/or user settings to the element.
3117 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3118 "projection-type", player->video360_metadata.projection_type, NULL);
3120 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3121 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3123 if (player->video360_metadata.full_pano_width_pixels &&
3124 player->video360_metadata.full_pano_height_pixels &&
3125 player->video360_metadata.cropped_area_image_width &&
3126 player->video360_metadata.cropped_area_image_height) {
3127 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3128 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3129 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3130 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3131 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3132 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3133 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3137 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3138 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3139 "horizontal-fov", player->video360_horizontal_fov,
3140 "vertical-fov", player->video360_vertical_fov, NULL);
3143 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3144 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3145 "zoom", 1.0f / player->video360_zoom, NULL);
3148 if (player->video360_yaw_radians <= M_PI &&
3149 player->video360_yaw_radians >= -M_PI &&
3150 player->video360_pitch_radians <= M_PI_2 &&
3151 player->video360_pitch_radians >= -M_PI_2) {
3152 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3153 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
3154 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
3155 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3156 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3157 "pose-yaw", player->video360_metadata.init_view_heading,
3158 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3161 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3162 "passthrough", !player->is_video360_enabled, NULL);
3169 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3171 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3172 GList *element_bucket = NULL;
3175 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3177 /* create video360 filter */
3178 if (player->is_360_feature_enabled && player->is_content_spherical) {
3179 LOGD("create video360 element");
3180 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3181 __mmplayer_gst_set_video360_property(player);
3185 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3186 LOGD("skip creating the videoconv and rotator");
3187 return MM_ERROR_NONE;
3190 /* in case of sw codec & overlay surface type, except 360 playback.
3191 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3192 LOGD("create video converter: %s", video_csc);
3193 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3195 /* set video rotator */
3196 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
3199 *bucket = element_bucket;
3201 return MM_ERROR_NONE;
3203 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3204 g_list_free(element_bucket);
3208 return MM_ERROR_PLAYER_INTERNAL;
3212 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3214 gchar *factory_name = NULL;
3216 switch (surface_type) {
3217 case MM_DISPLAY_SURFACE_OVERLAY:
3218 if (strlen(player->ini.videosink_element_overlay) > 0)
3219 factory_name = player->ini.videosink_element_overlay;
3221 case MM_DISPLAY_SURFACE_REMOTE:
3222 case MM_DISPLAY_SURFACE_NULL:
3223 if (strlen(player->ini.videosink_element_fake) > 0)
3224 factory_name = player->ini.videosink_element_fake;
3227 LOGE("unidentified surface type");
3231 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3232 return factory_name;
3236 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3238 gchar *factory_name = NULL;
3239 MMPlayerGstElement *videobin = NULL;
3244 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3246 videobin = player->pipeline->videobin;
3247 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3249 attrs = MMPLAYER_GET_ATTRS(player);
3251 LOGE("cannot get content attribute");
3252 return MM_ERROR_PLAYER_INTERNAL;
3255 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3256 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3257 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3259 /* support shard memory with S/W codec on HawkP */
3260 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3261 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3262 "use-tbm", use_tbm, NULL);
3266 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3267 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3270 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3272 LOGD("disable last-sample");
3273 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3276 if (player->set_mode.media_packet_video_stream) {
3278 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3279 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3280 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3282 __mmplayer_add_signal_connection(player,
3283 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3284 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3286 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3289 __mmplayer_add_signal_connection(player,
3290 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3291 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3293 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3297 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3298 return MM_ERROR_PLAYER_INTERNAL;
3300 if (videobin[MMPLAYER_V_SINK].gst) {
3301 GstPad *sink_pad = NULL;
3302 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3304 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3305 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3306 gst_object_unref(GST_OBJECT(sink_pad));
3308 LOGE("failed to get sink pad from videosink");
3312 return MM_ERROR_NONE;
3317 * - video overlay surface(arm/x86) : tizenwlsink
3320 __mmplayer_gst_create_video_sink_bin(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
3323 GList *element_bucket = NULL;
3324 MMPlayerGstElement *first_element = NULL;
3325 MMPlayerGstElement *videobin = NULL;
3326 gchar *videosink_factory_name = NULL;
3329 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3332 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3334 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3336 player->pipeline->videobin = videobin;
3339 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3340 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3341 if (!videobin[MMPLAYER_V_BIN].gst) {
3342 LOGE("failed to create videobin");
3346 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3349 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3350 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3352 /* additional setting for sink plug-in */
3353 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3354 LOGE("failed to set video property");
3358 /* store it as it's sink element */
3359 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3361 /* adding created elements to bin */
3362 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3363 LOGE("failed to add elements");
3367 /* Linking elements in the bucket by added order */
3368 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3369 LOGE("failed to link elements");
3373 /* get first element's sinkpad for creating ghostpad */
3374 first_element = (MMPlayerGstElement *)element_bucket->data;
3375 if (!first_element) {
3376 LOGE("failed to get first element from bucket");
3380 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3382 LOGE("failed to get pad from first element");
3386 /* create ghostpad */
3387 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3388 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3389 LOGE("failed to add ghostpad to videobin");
3392 gst_object_unref(pad);
3394 /* done. free allocated variables */
3395 g_list_free(element_bucket);
3399 return MM_ERROR_NONE;
3402 LOGE("ERROR : releasing videobin");
3403 g_list_free(element_bucket);
3406 gst_object_unref(GST_OBJECT(pad));
3408 /* release videobin with it's childs */
3409 if (videobin[MMPLAYER_V_BIN].gst)
3410 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3412 MMPLAYER_FREEIF(videobin);
3413 player->pipeline->videobin = NULL;
3415 return MM_ERROR_PLAYER_INTERNAL;
3418 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
3420 GList *element_bucket = NULL;
3421 MMPlayerGstElement *textbin = player->pipeline->textbin;
3423 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3424 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3425 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3426 "signal-handoffs", FALSE,
3429 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3430 __mmplayer_add_signal_connection(player,
3431 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3432 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3434 G_CALLBACK(__mmplayer_update_subtitle),
3437 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3438 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3440 if (!player->play_subtitle) {
3441 LOGD("add textbin sink as sink element of whole pipeline.\n");
3442 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3445 /* adding created elements to bin */
3446 LOGD("adding created elements to bin\n");
3447 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3448 LOGE("failed to add elements\n");
3452 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3453 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3454 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3456 /* linking elements in the bucket by added order. */
3457 LOGD("Linking elements in the bucket by added order.\n");
3458 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3459 LOGE("failed to link elements\n");
3463 /* done. free allocated variables */
3464 g_list_free(element_bucket);
3466 if (textbin[MMPLAYER_T_QUEUE].gst) {
3468 GstPad *ghostpad = NULL;
3470 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3472 LOGE("failed to get sink pad of text queue");
3476 ghostpad = gst_ghost_pad_new("text_sink", pad);
3477 gst_object_unref(pad);
3480 LOGE("failed to create ghostpad of textbin\n");
3484 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3485 LOGE("failed to add ghostpad to textbin\n");
3486 gst_object_unref(ghostpad);
3491 return MM_ERROR_NONE;
3494 g_list_free(element_bucket);
3496 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3497 LOGE("remove textbin sink from sink list");
3498 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3501 /* release element at __mmplayer_gst_create_text_sink_bin */
3502 return MM_ERROR_PLAYER_INTERNAL;
3505 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
3507 MMPlayerGstElement *textbin = NULL;
3508 GList *element_bucket = NULL;
3509 int surface_type = 0;
3514 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3517 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3519 LOGE("failed to allocate memory for textbin\n");
3520 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3524 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3525 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3526 if (!textbin[MMPLAYER_T_BIN].gst) {
3527 LOGE("failed to create textbin\n");
3532 player->pipeline->textbin = textbin;
3535 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3536 LOGD("surface type for subtitle : %d", surface_type);
3537 switch (surface_type) {
3538 case MM_DISPLAY_SURFACE_OVERLAY:
3539 case MM_DISPLAY_SURFACE_NULL:
3540 case MM_DISPLAY_SURFACE_REMOTE:
3541 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3542 LOGE("failed to make plain text elements\n");
3553 return MM_ERROR_NONE;
3557 LOGD("ERROR : releasing textbin\n");
3559 g_list_free(element_bucket);
3561 /* release signal */
3562 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3564 /* release element which are not added to bin */
3565 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3566 /* NOTE : skip bin */
3567 if (textbin[i].gst) {
3568 GstObject* parent = NULL;
3569 parent = gst_element_get_parent(textbin[i].gst);
3572 gst_object_unref(GST_OBJECT(textbin[i].gst));
3573 textbin[i].gst = NULL;
3575 gst_object_unref(GST_OBJECT(parent));
3580 /* release textbin with it's childs */
3581 if (textbin[MMPLAYER_T_BIN].gst)
3582 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3584 MMPLAYER_FREEIF(player->pipeline->textbin);
3585 player->pipeline->textbin = NULL;
3588 return MM_ERROR_PLAYER_INTERNAL;
3593 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
3595 MMPlayerGstElement* mainbin = NULL;
3596 MMPlayerGstElement* textbin = NULL;
3597 MMHandleType attrs = 0;
3598 GstElement *subsrc = NULL;
3599 GstElement *subparse = NULL;
3600 gchar *subtitle_uri = NULL;
3601 const gchar *charset = NULL;
3607 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3609 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3611 mainbin = player->pipeline->mainbin;
3613 attrs = MMPLAYER_GET_ATTRS(player);
3615 LOGE("cannot get content attribute\n");
3616 return MM_ERROR_PLAYER_INTERNAL;
3619 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3620 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3621 LOGE("subtitle uri is not proper filepath.\n");
3622 return MM_ERROR_PLAYER_INVALID_URI;
3625 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3626 LOGE("failed to get storage info of subtitle path");
3627 return MM_ERROR_PLAYER_INVALID_URI;
3630 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
3632 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3633 player->subtitle_language_list = NULL;
3634 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3636 /* create the subtitle source */
3637 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3639 LOGE("failed to create filesrc element\n");
3642 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3644 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3645 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3647 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3648 LOGW("failed to add queue\n");
3649 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3650 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3651 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3656 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3658 LOGE("failed to create subparse element\n");
3662 charset = util_get_charset(subtitle_uri);
3664 LOGD("detected charset is %s\n", charset);
3665 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3668 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3669 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3671 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3672 LOGW("failed to add subparse\n");
3673 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3674 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3675 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3679 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3680 LOGW("failed to link subsrc and subparse\n");
3684 player->play_subtitle = TRUE;
3685 player->adjust_subtitle_pos = 0;
3687 LOGD("play subtitle using subtitle file\n");
3689 if (player->pipeline->textbin == NULL) {
3690 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3691 LOGE("failed to create text sink bin. continuing without text\n");
3695 textbin = player->pipeline->textbin;
3697 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3698 LOGW("failed to add textbin\n");
3700 /* release signal */
3701 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3703 /* release textbin with it's childs */
3704 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3705 MMPLAYER_FREEIF(player->pipeline->textbin);
3706 player->pipeline->textbin = textbin = NULL;
3710 LOGD("link text input selector and textbin ghost pad");
3712 player->textsink_linked = 1;
3713 player->external_text_idx = 0;
3714 LOGI("textsink is linked");
3716 textbin = player->pipeline->textbin;
3717 LOGD("text bin has been created. reuse it.");
3718 player->external_text_idx = 1;
3721 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3722 LOGW("failed to link subparse and textbin\n");
3726 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3728 LOGE("failed to get sink pad from textsink to probe data");
3732 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3733 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3735 gst_object_unref(pad);
3738 /* create dot. for debugging */
3739 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3742 return MM_ERROR_NONE;
3745 /* release text pipeline resource */
3746 player->textsink_linked = 0;
3748 /* release signal */
3749 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3751 if (player->pipeline->textbin) {
3752 LOGE("remove textbin");
3754 /* release textbin with it's childs */
3755 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3756 MMPLAYER_FREEIF(player->pipeline->textbin);
3757 player->pipeline->textbin = NULL;
3761 /* release subtitle elem */
3762 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3763 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3765 return MM_ERROR_PLAYER_INTERNAL;
3769 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3771 mm_player_t* player = (mm_player_t*) data;
3772 MMMessageParamType msg = {0, };
3773 GstClockTime duration = 0;
3774 gpointer text = NULL;
3775 guint text_size = 0;
3776 gboolean ret = TRUE;
3777 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3781 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3782 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3784 if (player->is_subtitle_force_drop) {
3785 LOGW("subtitle is dropped forcedly.");
3789 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3790 text = mapinfo.data;
3791 text_size = mapinfo.size;
3792 duration = GST_BUFFER_DURATION(buffer);
3794 if (player->set_mode.subtitle_off) {
3795 LOGD("subtitle is OFF.\n");
3799 if (!text || (text_size == 0)) {
3800 LOGD("There is no subtitle to be displayed.\n");
3804 msg.data = (void *) text;
3805 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3807 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
3809 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3810 gst_buffer_unmap(buffer, &mapinfo);
3817 static GstPadProbeReturn
3818 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3820 mm_player_t *player = (mm_player_t *) u_data;
3821 GstClockTime cur_timestamp = 0;
3822 gint64 adjusted_timestamp = 0;
3823 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3825 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3827 if (player->set_mode.subtitle_off) {
3828 LOGD("subtitle is OFF.\n");
3832 if (player->adjust_subtitle_pos == 0) {
3833 LOGD("nothing to do");
3837 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3838 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3840 if (adjusted_timestamp < 0) {
3841 LOGD("adjusted_timestamp under zero");
3846 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3847 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3848 GST_TIME_ARGS(cur_timestamp),
3849 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3851 return GST_PAD_PROBE_OK;
3853 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
3857 /* check player and subtitlebin are created */
3858 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3859 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3861 if (position == 0) {
3862 LOGD("nothing to do\n");
3864 return MM_ERROR_NONE;
3868 case MM_PLAYER_POS_FORMAT_TIME:
3870 /* check current postion */
3871 player->adjust_subtitle_pos = position;
3873 LOGD("save adjust_subtitle_pos in player") ;
3879 LOGW("invalid format.\n");
3881 return MM_ERROR_INVALID_ARGUMENT;
3887 return MM_ERROR_NONE;
3891 * This function is to create audio or video pipeline for playing.
3893 * @param player [in] handle of player
3895 * @return This function returns zero on success.
3900 __mmplayer_gst_create_pipeline(mm_player_t* player)
3902 int ret = MM_ERROR_NONE;
3903 MMPlayerGstElement *mainbin = NULL;
3904 MMHandleType attrs = 0;
3907 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3909 /* get profile attribute */
3910 attrs = MMPLAYER_GET_ATTRS(player);
3912 LOGE("failed to get content attribute");
3916 /* create pipeline handles */
3917 if (player->pipeline) {
3918 LOGE("pipeline should be released before create new one");
3922 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
3923 if (player->pipeline == NULL)
3926 /* create mainbin */
3927 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
3928 if (mainbin == NULL)
3931 /* create pipeline */
3932 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3933 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3934 if (!mainbin[MMPLAYER_M_PIPE].gst) {
3935 LOGE("failed to create pipeline");
3940 player->pipeline->mainbin = mainbin;
3942 /* create the source and decoder elements */
3943 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3944 ret = __mmplayer_gst_build_es_pipeline(player);
3946 ret = __mmplayer_gst_build_pipeline(player);
3948 if (ret != MM_ERROR_NONE) {
3949 LOGE("failed to create some elements");
3953 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
3954 if (__mmplayer_check_subtitle(player)) {
3955 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE)
3956 LOGE("failed to create text pipeline");
3960 ret = __mmplayer_gst_add_bus_watch(player);
3961 if (ret != MM_ERROR_NONE) {
3962 LOGE("failed to add bus watch");
3967 return MM_ERROR_NONE;
3970 __mmplayer_gst_destroy_pipeline(player);
3971 return MM_ERROR_PLAYER_INTERNAL;
3975 __mmplayer_reset_gapless_state(mm_player_t* player)
3978 MMPLAYER_RETURN_IF_FAIL(player
3980 && player->pipeline->audiobin
3981 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
3983 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
3990 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
3993 int ret = MM_ERROR_NONE;
3997 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
3999 /* cleanup stuffs */
4000 MMPLAYER_FREEIF(player->type);
4001 player->no_more_pad = FALSE;
4002 player->num_dynamic_pad = 0;
4003 player->demux_pad_index = 0;
4005 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4006 player->subtitle_language_list = NULL;
4007 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4009 __mmplayer_reset_gapless_state(player);
4011 if (player->streamer) {
4012 __mm_player_streaming_deinitialize(player->streamer);
4013 __mm_player_streaming_destroy(player->streamer);
4014 player->streamer = NULL;
4017 /* cleanup unlinked mime type */
4018 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4019 MMPLAYER_FREEIF(player->unlinked_video_mime);
4020 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4022 /* cleanup running stuffs */
4023 __mmplayer_cancel_eos_timer(player);
4025 /* cleanup gst stuffs */
4026 if (player->pipeline) {
4027 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
4028 GstTagList* tag_list = player->pipeline->tag_list;
4030 /* first we need to disconnect all signal hander */
4031 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4034 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4035 MMPlayerGstElement* videobin = player->pipeline->videobin;
4036 MMPlayerGstElement* textbin = player->pipeline->textbin;
4037 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4038 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4039 gst_object_unref(bus);
4041 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4042 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4043 if (ret != MM_ERROR_NONE) {
4044 LOGE("fail to change state to NULL\n");
4045 return MM_ERROR_PLAYER_INTERNAL;
4048 LOGW("succeeded in changing state to NULL\n");
4050 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4053 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4054 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4056 /* free avsysaudiosink
4057 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4058 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4060 MMPLAYER_FREEIF(audiobin);
4061 MMPLAYER_FREEIF(videobin);
4062 MMPLAYER_FREEIF(textbin);
4063 MMPLAYER_FREEIF(mainbin);
4067 gst_tag_list_unref(tag_list);
4069 MMPLAYER_FREEIF(player->pipeline);
4071 MMPLAYER_FREEIF(player->album_art);
4073 if (player->v_stream_caps) {
4074 gst_caps_unref(player->v_stream_caps);
4075 player->v_stream_caps = NULL;
4077 if (player->a_stream_caps) {
4078 gst_caps_unref(player->a_stream_caps);
4079 player->a_stream_caps = NULL;
4082 if (player->s_stream_caps) {
4083 gst_caps_unref(player->s_stream_caps);
4084 player->s_stream_caps = NULL;
4086 __mmplayer_track_destroy(player);
4088 if (player->sink_elements)
4089 g_list_free(player->sink_elements);
4090 player->sink_elements = NULL;
4092 if (player->bufmgr) {
4093 tbm_bufmgr_deinit(player->bufmgr);
4094 player->bufmgr = NULL;
4097 LOGW("finished destroy pipeline\n");
4104 static int __mmplayer_gst_realize(mm_player_t* player)
4107 int ret = MM_ERROR_NONE;
4111 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4113 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4115 ret = __mmplayer_gst_create_pipeline(player);
4117 LOGE("failed to create pipeline\n");
4121 /* set pipeline state to READY */
4122 /* NOTE : state change to READY must be performed sync. */
4123 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4124 ret = __mmplayer_gst_set_state(player,
4125 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4127 if (ret != MM_ERROR_NONE) {
4128 /* return error if failed to set state */
4129 LOGE("failed to set READY state");
4133 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4135 /* create dot before error-return. for debugging */
4136 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4143 static int __mmplayer_gst_unrealize(mm_player_t* player)
4145 int ret = MM_ERROR_NONE;
4149 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4151 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4152 MMPLAYER_PRINT_STATE(player);
4154 /* release miscellaneous information */
4155 __mmplayer_release_misc(player);
4157 /* destroy pipeline */
4158 ret = __mmplayer_gst_destroy_pipeline(player);
4159 if (ret != MM_ERROR_NONE) {
4160 LOGE("failed to destory pipeline\n");
4164 /* release miscellaneous information.
4165 these info needs to be released after pipeline is destroyed. */
4166 __mmplayer_release_misc_post(player);
4168 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4176 __mmplayer_gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
4181 LOGW("set_message_callback is called with invalid player handle\n");
4182 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4185 player->msg_cb = callback;
4186 player->msg_cb_param = user_param;
4188 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
4192 return MM_ERROR_NONE;
4195 int __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
4197 int ret = MM_ERROR_NONE;
4202 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4203 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4204 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4206 memset(data, 0, sizeof(MMPlayerParseProfile));
4208 if (strstr(uri, "es_buff://")) {
4209 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4210 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4211 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4212 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4214 tmp = g_ascii_strdown(uri, strlen(uri));
4215 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4216 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4218 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4220 } else if (strstr(uri, "mms://")) {
4221 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4222 } else if ((path = strstr(uri, "mem://"))) {
4223 ret = __mmplayer_set_mem_uri(data, path, param);
4225 ret = __mmplayer_set_file_uri(data, uri);
4228 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4229 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4230 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4231 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4233 /* dump parse result */
4234 SECURE_LOGW("incoming uri : %s\n", uri);
4235 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
4236 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4244 __mmplayer_can_do_interrupt(mm_player_t *player)
4246 if (!player || !player->pipeline || !player->attrs) {
4247 LOGW("not initialized");
4251 if (player->audio_stream_render_cb) {
4252 LOGW("not support in pcm extraction mode");
4256 /* check if seeking */
4257 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4258 MMMessageParamType msg_param;
4259 memset(&msg_param, 0, sizeof(MMMessageParamType));
4260 msg_param.code = MM_ERROR_PLAYER_SEEK;
4261 player->seek_state = MMPLAYER_SEEK_NONE;
4262 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4266 /* check other thread */
4267 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4268 LOGW("locked already, cmd state : %d", player->cmd);
4270 /* check application command */
4271 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4272 LOGW("playing.. should wait cmd lock then, will be interrupted");
4274 /* lock will be released at mrp_resource_release_cb() */
4275 MMPLAYER_CMD_LOCK(player);
4278 LOGW("nothing to do");
4281 LOGW("can interrupt immediately");
4285 FAILED: /* with CMD UNLOCKED */
4288 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4293 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4296 mm_player_t *player = NULL;
4300 if (user_data == NULL) {
4301 LOGE("- user_data is null\n");
4304 player = (mm_player_t *)user_data;
4306 /* do something to release resource here.
4307 * player stop and interrupt forwarding */
4308 if (!__mmplayer_can_do_interrupt(player)) {
4309 LOGW("no need to interrupt, so leave");
4311 MMMessageParamType msg = {0, };
4314 player->interrupted_by_resource = TRUE;
4316 /* get last play position */
4317 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4318 LOGW("failed to get play position.");
4320 msg.union_type = MM_MSG_UNION_TIME;
4321 msg.time.elapsed = pos;
4322 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4324 LOGD("video resource conflict so, resource will be freed by unrealizing");
4325 if (_mmplayer_unrealize((MMHandleType)player))
4326 LOGW("failed to unrealize");
4328 /* lock is called in __mmplayer_can_do_interrupt() */
4329 MMPLAYER_CMD_UNLOCK(player);
4332 if (res == player->video_overlay_resource)
4333 player->video_overlay_resource = FALSE;
4335 player->video_decoder_resource = FALSE;
4343 __mmplayer_initialize_video_roi(mm_player_t *player)
4345 player->video_roi.scale_x = 0.0;
4346 player->video_roi.scale_y = 0.0;
4347 player->video_roi.scale_width = 1.0;
4348 player->video_roi.scale_height = 1.0;
4352 _mmplayer_create_player(MMHandleType handle)
4354 int ret = MM_ERROR_PLAYER_INTERNAL;
4355 bool enabled = false;
4357 mm_player_t* player = MM_PLAYER_CAST(handle);
4361 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4363 /* initialize player state */
4364 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4365 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4366 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4367 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4369 /* check current state */
4370 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4372 /* construct attributes */
4373 player->attrs = _mmplayer_construct_attribute(handle);
4375 if (!player->attrs) {
4376 LOGE("Failed to construct attributes\n");
4380 /* initialize gstreamer with configured parameter */
4381 if (!__mmplayer_init_gstreamer(player)) {
4382 LOGE("Initializing gstreamer failed\n");
4383 _mmplayer_deconstruct_attribute(handle);
4387 /* create lock. note that g_tread_init() has already called in gst_init() */
4388 g_mutex_init(&player->fsink_lock);
4390 /* create update tag lock */
4391 g_mutex_init(&player->update_tag_lock);
4393 /* create gapless play mutex */
4394 g_mutex_init(&player->gapless_play_thread_mutex);
4396 /* create gapless play cond */
4397 g_cond_init(&player->gapless_play_thread_cond);
4399 /* create gapless play thread */
4400 player->gapless_play_thread =
4401 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4402 if (!player->gapless_play_thread) {
4403 LOGE("failed to create gapless play thread");
4404 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4405 g_mutex_clear(&player->gapless_play_thread_mutex);
4406 g_cond_clear(&player->gapless_play_thread_cond);
4410 player->bus_msg_q = g_queue_new();
4411 if (!player->bus_msg_q) {
4412 LOGE("failed to create queue for bus_msg");
4413 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4417 ret = _mmplayer_initialize_video_capture(player);
4418 if (ret != MM_ERROR_NONE) {
4419 LOGE("failed to initialize video capture\n");
4423 /* initialize resource manager */
4424 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
4425 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
4426 &player->resource_manager)) {
4427 LOGE("failed to initialize resource manager\n");
4428 ret = MM_ERROR_PLAYER_INTERNAL;
4432 /* create video bo lock and cond */
4433 g_mutex_init(&player->video_bo_mutex);
4434 g_cond_init(&player->video_bo_cond);
4436 /* create media stream callback mutex */
4437 g_mutex_init(&player->media_stream_cb_lock);
4439 /* create subtitle info lock and cond */
4440 g_mutex_init(&player->subtitle_info_mutex);
4441 g_cond_init(&player->subtitle_info_cond);
4443 player->streaming_type = STREAMING_SERVICE_NONE;
4445 /* give default value of audio effect setting */
4446 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4447 player->sound.rg_enable = false;
4448 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4450 player->play_subtitle = FALSE;
4451 player->has_closed_caption = FALSE;
4452 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4453 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4454 player->pending_resume = FALSE;
4455 if (player->ini.dump_element_keyword[0][0] == '\0')
4456 player->ini.set_dump_element_flag = FALSE;
4458 player->ini.set_dump_element_flag = TRUE;
4460 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4461 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4462 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4464 /* Set video360 settings to their defaults for just-created player.
4467 player->is_360_feature_enabled = FALSE;
4468 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4469 LOGI("spherical feature info: %d", enabled);
4471 player->is_360_feature_enabled = TRUE;
4473 LOGE("failed to get spherical feature info");
4476 player->is_content_spherical = FALSE;
4477 player->is_video360_enabled = TRUE;
4478 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4479 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4480 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4481 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4482 player->video360_zoom = 1.0f;
4483 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4484 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4486 __mmplayer_initialize_video_roi(player);
4488 /* set player state to null */
4489 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4490 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4492 return MM_ERROR_NONE;
4496 g_mutex_clear(&player->fsink_lock);
4498 /* free update tag lock */
4499 g_mutex_clear(&player->update_tag_lock);
4501 g_queue_free(player->bus_msg_q);
4503 /* free gapless play thread */
4504 if (player->gapless_play_thread) {
4505 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4506 player->gapless_play_thread_exit = TRUE;
4507 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4508 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4510 g_thread_join(player->gapless_play_thread);
4511 player->gapless_play_thread = NULL;
4513 g_mutex_clear(&player->gapless_play_thread_mutex);
4514 g_cond_clear(&player->gapless_play_thread_cond);
4517 /* release attributes */
4518 _mmplayer_deconstruct_attribute(handle);
4526 __mmplayer_init_gstreamer(mm_player_t* player)
4528 static gboolean initialized = FALSE;
4529 static const int max_argc = 50;
4531 gchar** argv = NULL;
4532 gchar** argv2 = NULL;
4538 LOGD("gstreamer already initialized.\n");
4543 argc = malloc(sizeof(int));
4544 argv = malloc(sizeof(gchar*) * max_argc);
4545 argv2 = malloc(sizeof(gchar*) * max_argc);
4547 if (!argc || !argv || !argv2)
4550 memset(argv, 0, sizeof(gchar*) * max_argc);
4551 memset(argv2, 0, sizeof(gchar*) * max_argc);
4555 argv[0] = g_strdup("mmplayer");
4558 for (i = 0; i < 5; i++) {
4559 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4560 if (strlen(player->ini.gst_param[i]) > 0) {
4561 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4566 /* we would not do fork for scanning plugins */
4567 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4570 /* check disable registry scan */
4571 if (player->ini.skip_rescan) {
4572 argv[*argc] = g_strdup("--gst-disable-registry-update");
4576 /* check disable segtrap */
4577 if (player->ini.disable_segtrap) {
4578 argv[*argc] = g_strdup("--gst-disable-segtrap");
4582 LOGD("initializing gstreamer with following parameter\n");
4583 LOGD("argc : %d\n", *argc);
4586 for (i = 0; i < arg_count; i++) {
4588 LOGD("argv[%d] : %s\n", i, argv2[i]);
4591 /* initializing gstreamer */
4592 if (!gst_init_check(argc, &argv, &err)) {
4593 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
4600 for (i = 0; i < arg_count; i++) {
4601 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
4602 MMPLAYER_FREEIF(argv2[i]);
4605 MMPLAYER_FREEIF(argv);
4606 MMPLAYER_FREEIF(argv2);
4607 MMPLAYER_FREEIF(argc);
4617 for (i = 0; i < arg_count; i++) {
4618 LOGD("free[%d] : %s\n", i, argv2[i]);
4619 MMPLAYER_FREEIF(argv2[i]);
4622 MMPLAYER_FREEIF(argv);
4623 MMPLAYER_FREEIF(argv2);
4624 MMPLAYER_FREEIF(argc);
4630 __mmplayer_check_async_state_transition(mm_player_t* player)
4632 GstState element_state = GST_STATE_VOID_PENDING;
4633 GstState element_pending_state = GST_STATE_VOID_PENDING;
4634 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4635 GstElement * element = NULL;
4636 gboolean async = FALSE;
4638 /* check player handle */
4639 MMPLAYER_RETURN_IF_FAIL(player &&
4641 player->pipeline->mainbin &&
4642 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4645 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4647 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4648 LOGD("don't need to check the pipeline state");
4652 MMPLAYER_PRINT_STATE(player);
4654 /* wait for state transition */
4655 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4656 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
4658 if (ret == GST_STATE_CHANGE_FAILURE) {
4659 LOGE(" [%s] state : %s pending : %s \n",
4660 GST_ELEMENT_NAME(element),
4661 gst_element_state_get_name(element_state),
4662 gst_element_state_get_name(element_pending_state));
4664 /* dump state of all element */
4665 __mmplayer_dump_pipeline_state(player);
4670 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
4675 _mmplayer_destroy(MMHandleType handle)
4677 mm_player_t* player = MM_PLAYER_CAST(handle);
4681 /* check player handle */
4682 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4684 /* destroy can called at anytime */
4685 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4687 /* check async state transition */
4688 __mmplayer_check_async_state_transition(player);
4690 /* release gapless play thread */
4691 if (player->gapless_play_thread) {
4692 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4693 player->gapless_play_thread_exit = TRUE;
4694 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4695 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4697 LOGD("waitting for gapless play thread exit\n");
4698 g_thread_join(player->gapless_play_thread);
4699 g_mutex_clear(&player->gapless_play_thread_mutex);
4700 g_cond_clear(&player->gapless_play_thread_cond);
4701 LOGD("gapless play thread released\n");
4704 _mmplayer_release_video_capture(player);
4706 /* de-initialize resource manager */
4707 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4708 player->resource_manager))
4709 LOGE("failed to deinitialize resource manager\n");
4711 /* release pipeline */
4712 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4713 LOGE("failed to destory pipeline\n");
4714 return MM_ERROR_PLAYER_INTERNAL;
4717 g_queue_free(player->bus_msg_q);
4719 /* release subtitle info lock and cond */
4720 g_mutex_clear(&player->subtitle_info_mutex);
4721 g_cond_clear(&player->subtitle_info_cond);
4723 __mmplayer_release_dump_list(player->dump_list);
4725 /* release miscellaneous information */
4726 __mmplayer_release_misc(player);
4728 /* release miscellaneous information.
4729 these info needs to be released after pipeline is destroyed. */
4730 __mmplayer_release_misc_post(player);
4732 /* release attributes */
4733 _mmplayer_deconstruct_attribute(handle);
4736 g_mutex_clear(&player->fsink_lock);
4739 g_mutex_clear(&player->update_tag_lock);
4741 /* release video bo lock and cond */
4742 g_mutex_clear(&player->video_bo_mutex);
4743 g_cond_clear(&player->video_bo_cond);
4745 /* release media stream callback lock */
4746 g_mutex_clear(&player->media_stream_cb_lock);
4750 return MM_ERROR_NONE;
4754 _mmplayer_realize(MMHandleType hplayer)
4756 mm_player_t* player = (mm_player_t*)hplayer;
4759 MMHandleType attrs = 0;
4760 int ret = MM_ERROR_NONE;
4764 /* check player handle */
4765 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4767 /* check current state */
4768 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4770 attrs = MMPLAYER_GET_ATTRS(player);
4772 LOGE("fail to get attributes.\n");
4773 return MM_ERROR_PLAYER_INTERNAL;
4775 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4776 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4778 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4779 ret = __mmplayer_parse_profile((const char*)uri, param, &player->profile);
4781 if (ret != MM_ERROR_NONE) {
4782 LOGE("failed to parse profile");
4787 if (uri && (strstr(uri, "es_buff://"))) {
4788 if (strstr(uri, "es_buff://push_mode"))
4789 player->es_player_push_mode = TRUE;
4791 player->es_player_push_mode = FALSE;
4794 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4795 LOGW("mms protocol is not supported format.\n");
4796 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4799 if (MMPLAYER_IS_STREAMING(player))
4800 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4802 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4804 player->smooth_streaming = FALSE;
4805 player->videodec_linked = 0;
4806 player->audiodec_linked = 0;
4807 player->textsink_linked = 0;
4808 player->is_external_subtitle_present = FALSE;
4809 player->is_external_subtitle_added_now = FALSE;
4810 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4811 player->video360_metadata.is_spherical = -1;
4812 player->is_openal_plugin_used = FALSE;
4813 player->demux_pad_index = 0;
4814 player->subtitle_language_list = NULL;
4815 player->is_subtitle_force_drop = FALSE;
4816 player->last_multiwin_status = FALSE;
4818 __mmplayer_track_initialize(player);
4819 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4821 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4822 player->streamer = __mm_player_streaming_create();
4823 __mm_player_streaming_initialize(player->streamer);
4826 /* realize pipeline */
4827 ret = __mmplayer_gst_realize(player);
4828 if (ret != MM_ERROR_NONE)
4829 LOGE("fail to realize the player.\n");
4831 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4839 _mmplayer_unrealize(MMHandleType hplayer)
4841 mm_player_t* player = (mm_player_t*)hplayer;
4842 int ret = MM_ERROR_NONE;
4846 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4848 MMPLAYER_CMD_UNLOCK(player);
4849 /* destroy the gst bus msg thread which is created during realize.
4850 this funct have to be called before getting cmd lock. */
4851 __mmplayer_bus_msg_thread_destroy(player);
4852 MMPLAYER_CMD_LOCK(player);
4854 /* check current state */
4855 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4857 /* check async state transition */
4858 __mmplayer_check_async_state_transition(player);
4860 /* unrealize pipeline */
4861 ret = __mmplayer_gst_unrealize(player);
4863 /* set asm stop if success */
4864 if (MM_ERROR_NONE == ret) {
4865 if (!player->interrupted_by_resource) {
4866 if (player->video_decoder_resource != NULL) {
4867 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4868 player->video_decoder_resource);
4869 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4870 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
4872 player->video_decoder_resource = NULL;
4875 if (player->video_overlay_resource != NULL) {
4876 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4877 player->video_overlay_resource);
4878 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4879 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
4881 player->video_overlay_resource = NULL;
4884 ret = mm_resource_manager_commit(player->resource_manager);
4885 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4886 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
4889 LOGE("failed and don't change asm state to stop");
4897 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
4899 mm_player_t* player = (mm_player_t*)hplayer;
4901 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4903 return __mmplayer_gst_set_message_callback(player, callback, user_param);
4907 _mmplayer_get_state(MMHandleType hplayer, int* state)
4909 mm_player_t *player = (mm_player_t*)hplayer;
4911 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
4913 *state = MMPLAYER_CURRENT_STATE(player);
4915 return MM_ERROR_NONE;
4920 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
4922 mm_player_t* player = (mm_player_t*) hplayer;
4923 GstElement* vol_element = NULL;
4928 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4930 LOGD("volume [L]=%f:[R]=%f\n",
4931 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
4933 /* invalid factor range or not */
4934 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
4935 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
4936 LOGE("Invalid factor!(valid factor:0~1.0)\n");
4937 return MM_ERROR_INVALID_ARGUMENT;
4941 /* not support to set other value into each channel */
4942 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
4943 return MM_ERROR_INVALID_ARGUMENT;
4945 /* Save volume to handle. Currently the first array element will be saved. */
4946 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
4948 /* check pipeline handle */
4949 if (!player->pipeline || !player->pipeline->audiobin) {
4950 LOGD("audiobin is not created yet\n");
4951 LOGD("but, current stored volume will be set when it's created.\n");
4953 /* NOTE : stored volume will be used in create_audiobin
4954 * returning MM_ERROR_NONE here makes application to able to
4955 * set volume at anytime.
4957 return MM_ERROR_NONE;
4960 /* setting volume to volume element */
4961 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
4964 LOGD("volume is set [%f]\n", player->sound.volume);
4965 g_object_set(vol_element, "volume", player->sound.volume, NULL);
4970 return MM_ERROR_NONE;
4975 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
4977 mm_player_t* player = (mm_player_t*) hplayer;
4982 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4983 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
4985 /* returning stored volume */
4986 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
4987 volume->level[i] = player->sound.volume;
4991 return MM_ERROR_NONE;
4995 _mmplayer_set_mute(MMHandleType hplayer, int mute)
4997 mm_player_t* player = (mm_player_t*) hplayer;
4998 GstElement* vol_element = NULL;
5002 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5004 /* mute value shoud 0 or 1 */
5005 if (mute != 0 && mute != 1) {
5006 LOGE("bad mute value\n");
5008 /* FIXIT : definitly, we need _BAD_PARAM error code */
5009 return MM_ERROR_INVALID_ARGUMENT;
5012 player->sound.mute = mute;
5014 /* just hold mute value if pipeline is not ready */
5015 if (!player->pipeline || !player->pipeline->audiobin) {
5016 LOGD("pipeline is not ready. holding mute value\n");
5017 return MM_ERROR_NONE;
5020 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5022 /* NOTE : volume will only created when the bt is enabled */
5024 LOGD("mute : %d\n", mute);
5025 g_object_set(vol_element, "mute", mute, NULL);
5027 LOGD("volume elemnet is not created. using volume in audiosink\n");
5031 return MM_ERROR_NONE;
5035 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
5037 mm_player_t* player = (mm_player_t*) hplayer;
5041 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5042 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5044 /* just hold mute value if pipeline is not ready */
5045 if (!player->pipeline || !player->pipeline->audiobin) {
5046 LOGD("pipeline is not ready. returning stored value\n");
5047 *pmute = player->sound.mute;
5048 return MM_ERROR_NONE;
5051 *pmute = player->sound.mute;
5055 return MM_ERROR_NONE;
5059 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5061 mm_player_t* player = (mm_player_t*) hplayer;
5065 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5067 player->video_stream_changed_cb = callback;
5068 player->video_stream_changed_cb_user_param = user_param;
5069 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
5073 return MM_ERROR_NONE;
5077 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5079 mm_player_t* player = (mm_player_t*) hplayer;
5083 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5085 player->audio_stream_changed_cb = callback;
5086 player->audio_stream_changed_cb_user_param = user_param;
5087 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
5091 return MM_ERROR_NONE;
5095 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5097 mm_player_t *player = (mm_player_t*) hplayer;
5101 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5103 player->audio_stream_render_cb = callback;
5104 player->audio_stream_cb_user_param = user_param;
5105 player->audio_stream_sink_sync = sync;
5106 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5110 return MM_ERROR_NONE;
5114 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5116 mm_player_t* player = (mm_player_t*) hplayer;
5120 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5122 if (callback && !player->bufmgr)
5123 player->bufmgr = tbm_bufmgr_init(-1);
5125 player->set_mode.media_packet_video_stream = (callback) ? true : false;
5126 player->video_stream_cb = callback;
5127 player->video_stream_cb_user_param = user_param;
5129 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5133 return MM_ERROR_NONE;
5137 _mmplayer_start(MMHandleType hplayer)
5139 mm_player_t* player = (mm_player_t*) hplayer;
5140 gint ret = MM_ERROR_NONE;
5144 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5146 /* check current state */
5147 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5149 /* start pipeline */
5150 ret = __mmplayer_gst_start(player);
5151 if (ret != MM_ERROR_NONE)
5152 LOGE("failed to start player.\n");
5154 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5155 LOGD("force playing start even during buffering");
5156 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5164 /* NOTE: post "not supported codec message" to application
5165 * when one codec is not found during AUTOPLUGGING in MSL.
5166 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5167 * And, if any codec is not found, don't send message here.
5168 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5171 __mmplayer_handle_missed_plugin(mm_player_t* player)
5173 MMMessageParamType msg_param;
5174 memset(&msg_param, 0, sizeof(MMMessageParamType));
5175 gboolean post_msg_direct = FALSE;
5179 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5181 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
5182 player->not_supported_codec, player->can_support_codec);
5184 if (player->not_found_demuxer) {
5185 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5186 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5188 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5189 MMPLAYER_FREEIF(msg_param.data);
5191 return MM_ERROR_NONE;
5194 if (player->not_supported_codec) {
5195 if (player->can_support_codec) {
5196 // There is one codec to play
5197 post_msg_direct = TRUE;
5199 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5200 post_msg_direct = TRUE;
5203 if (post_msg_direct) {
5204 MMMessageParamType msg_param;
5205 memset(&msg_param, 0, sizeof(MMMessageParamType));
5207 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5208 LOGW("not found AUDIO codec, posting error code to application.\n");
5210 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5211 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5212 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5213 LOGW("not found VIDEO codec, posting error code to application.\n");
5215 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5216 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5219 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5221 MMPLAYER_FREEIF(msg_param.data);
5223 return MM_ERROR_NONE;
5225 // no any supported codec case
5226 LOGW("not found any codec, posting error code to application.\n");
5228 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5229 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5230 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5232 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5233 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5236 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5238 MMPLAYER_FREEIF(msg_param.data);
5244 return MM_ERROR_NONE;
5247 static void __mmplayer_check_pipeline(mm_player_t* player)
5249 GstState element_state = GST_STATE_VOID_PENDING;
5250 GstState element_pending_state = GST_STATE_VOID_PENDING;
5252 int ret = MM_ERROR_NONE;
5254 if (player->gapless.reconfigure) {
5255 LOGW("pipeline is under construction.\n");
5257 MMPLAYER_PLAYBACK_LOCK(player);
5258 MMPLAYER_PLAYBACK_UNLOCK(player);
5260 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5262 /* wait for state transition */
5263 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5265 if (ret == GST_STATE_CHANGE_FAILURE)
5266 LOGE("failed to change pipeline state within %d sec\n", timeout);
5270 /* NOTE : it should be able to call 'stop' anytime*/
5272 _mmplayer_stop(MMHandleType hplayer)
5274 mm_player_t* player = (mm_player_t*)hplayer;
5275 int ret = MM_ERROR_NONE;
5279 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5281 /* check current state */
5282 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5284 /* check pipline building state */
5285 __mmplayer_check_pipeline(player);
5286 __mmplayer_reset_gapless_state(player);
5288 /* NOTE : application should not wait for EOS after calling STOP */
5289 __mmplayer_cancel_eos_timer(player);
5292 player->seek_state = MMPLAYER_SEEK_NONE;
5295 ret = __mmplayer_gst_stop(player);
5297 if (ret != MM_ERROR_NONE)
5298 LOGE("failed to stop player.\n");
5306 _mmplayer_pause(MMHandleType hplayer)
5308 mm_player_t* player = (mm_player_t*)hplayer;
5309 gint64 pos_nsec = 0;
5310 gboolean async = FALSE;
5311 gint ret = MM_ERROR_NONE;
5315 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5317 /* check current state */
5318 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5320 /* check pipline building state */
5321 __mmplayer_check_pipeline(player);
5323 switch (MMPLAYER_CURRENT_STATE(player)) {
5324 case MM_PLAYER_STATE_READY:
5326 /* check prepare async or not.
5327 * In the case of streaming playback, it's recommned to avoid blocking wait.
5329 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5330 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5332 /* Changing back sync of rtspsrc to async */
5333 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5334 LOGD("async prepare working mode for rtsp");
5340 case MM_PLAYER_STATE_PLAYING:
5342 /* NOTE : store current point to overcome some bad operation
5343 *(returning zero when getting current position in paused state) of some
5346 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5347 LOGW("getting current position failed in paused\n");
5349 player->last_position = pos_nsec;
5351 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5352 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5353 This causes problem is position calculation during normal pause resume scenarios also.
5354 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5355 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5356 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5357 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5363 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5364 LOGD("doing async pause in case of ms buff src");
5368 /* pause pipeline */
5369 ret = __mmplayer_gst_pause(player, async);
5371 if (ret != MM_ERROR_NONE)
5372 LOGE("failed to pause player. ret : 0x%x\n", ret);
5374 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5375 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5376 LOGE("failed to update display_rotation");
5384 /* in case of streaming, pause could take long time.*/
5386 _mmplayer_abort_pause(MMHandleType hplayer)
5388 mm_player_t* player = (mm_player_t*)hplayer;
5389 int ret = MM_ERROR_NONE;
5393 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5395 player->pipeline->mainbin,
5396 MM_ERROR_PLAYER_NOT_INITIALIZED);
5398 LOGD("set the pipeline state to READY");
5400 /* set state to READY */
5401 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5402 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5403 if (ret != MM_ERROR_NONE) {
5404 LOGE("fail to change state to READY");
5405 return MM_ERROR_PLAYER_INTERNAL;
5408 LOGD("succeeded in changing state to READY");
5414 _mmplayer_resume(MMHandleType hplayer)
5416 mm_player_t* player = (mm_player_t*)hplayer;
5417 int ret = MM_ERROR_NONE;
5418 gboolean async = FALSE;
5422 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5424 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5425 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5426 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5430 /* Changing back sync mode rtspsrc to async */
5431 LOGD("async resume for rtsp case");
5435 /* check current state */
5436 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5438 ret = __mmplayer_gst_resume(player, async);
5439 if (ret != MM_ERROR_NONE)
5440 LOGE("failed to resume player.\n");
5442 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5443 LOGD("force resume even during buffering");
5444 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5453 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5455 mm_player_t* player = (mm_player_t*)hplayer;
5456 gint64 pos_nsec = 0;
5457 int ret = MM_ERROR_NONE;
5459 signed long long start = 0, stop = 0;
5460 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5463 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5464 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5466 /* The sound of video is not supported under 0.0 and over 2.0. */
5467 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5468 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5471 _mmplayer_set_mute(hplayer, mute);
5473 if (player->playback_rate == rate)
5474 return MM_ERROR_NONE;
5476 /* If the position is reached at start potion during fast backward, EOS is posted.
5477 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5479 player->playback_rate = rate;
5481 current_state = MMPLAYER_CURRENT_STATE(player);
5483 if (current_state != MM_PLAYER_STATE_PAUSED)
5484 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5486 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5488 if ((current_state == MM_PLAYER_STATE_PAUSED)
5489 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5490 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5491 pos_nsec = player->last_position;
5496 stop = GST_CLOCK_TIME_NONE;
5498 start = GST_CLOCK_TIME_NONE;
5502 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5503 player->playback_rate,
5505 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5506 GST_SEEK_TYPE_SET, start,
5507 GST_SEEK_TYPE_SET, stop)) {
5508 LOGE("failed to set speed playback\n");
5509 return MM_ERROR_PLAYER_SEEK;
5512 LOGD("succeeded to set speed playback as %0.1f\n", rate);
5516 return MM_ERROR_NONE;;
5520 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5522 mm_player_t* player = (mm_player_t*)hplayer;
5523 int ret = MM_ERROR_NONE;
5527 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5529 /* check pipline building state */
5530 __mmplayer_check_pipeline(player);
5532 ret = __mmplayer_gst_set_position(player, position, FALSE);
5540 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5542 mm_player_t* player = (mm_player_t*)hplayer;
5543 int ret = MM_ERROR_NONE;
5545 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5547 ret = __mmplayer_gst_get_position(player, position);
5553 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5555 mm_player_t* player = (mm_player_t*)hplayer;
5556 int ret = MM_ERROR_NONE;
5558 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5559 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5561 *duration = player->duration;
5566 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
5568 mm_player_t* player = (mm_player_t*)hplayer;
5569 int ret = MM_ERROR_NONE;
5571 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5573 ret = __mmplayer_gst_get_buffer_position(player, format, start_pos, stop_pos);
5579 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5581 mm_player_t* player = (mm_player_t*)hplayer;
5582 int ret = MM_ERROR_NONE;
5586 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5588 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5596 __mmplayer_is_midi_type(gchar* str_caps)
5598 if ((g_strrstr(str_caps, "audio/midi")) ||
5599 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5600 (g_strrstr(str_caps, "application/x-smaf")) ||
5601 (g_strrstr(str_caps, "audio/x-imelody")) ||
5602 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5603 (g_strrstr(str_caps, "audio/xmf")) ||
5604 (g_strrstr(str_caps, "audio/mxmf"))) {
5613 __mmplayer_is_only_mp3_type(gchar *str_caps)
5615 if (g_strrstr(str_caps, "application/x-id3") ||
5616 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5622 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
5624 GstStructure* caps_structure = NULL;
5625 gint samplerate = 0;
5629 MMPLAYER_RETURN_IF_FAIL(player && caps);
5631 caps_structure = gst_caps_get_structure(caps, 0);
5633 /* set stream information */
5634 gst_structure_get_int(caps_structure, "rate", &samplerate);
5635 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5637 gst_structure_get_int(caps_structure, "channels", &channels);
5638 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5640 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
5644 __mmplayer_update_content_type_info(mm_player_t* player)
5647 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5649 if (__mmplayer_is_midi_type(player->type)) {
5650 player->bypass_audio_effect = TRUE;
5651 } else if (g_strrstr(player->type, "application/x-hls")) {
5652 /* If it can't know exact type when it parses uri because of redirection case,
5653 * it will be fixed by typefinder or when doing autoplugging.
5655 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5656 if (player->streamer) {
5657 player->streamer->is_adaptive_streaming = TRUE;
5658 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5659 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
5661 } else if (g_strrstr(player->type, "application/dash+xml")) {
5662 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5663 if (player->streamer) {
5664 player->streamer->is_adaptive_streaming = TRUE;
5665 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5669 LOGD("uri type : %d", player->profile.uri_type);
5674 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5675 GstCaps *caps, gpointer data)
5677 mm_player_t* player = (mm_player_t*)data;
5682 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5684 /* store type string */
5685 MMPLAYER_FREEIF(player->type);
5686 player->type = gst_caps_to_string(caps);
5688 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
5689 player, player->type, probability, gst_caps_get_size(caps));
5692 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5693 (g_strrstr(player->type, "audio/x-raw-int"))) {
5694 LOGE("not support media format\n");
5696 if (player->msg_posted == FALSE) {
5697 MMMessageParamType msg_param;
5698 memset(&msg_param, 0, sizeof(MMMessageParamType));
5700 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5701 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5703 /* don't post more if one was sent already */
5704 player->msg_posted = TRUE;
5709 __mmplayer_update_content_type_info(player);
5711 pad = gst_element_get_static_pad(tf, "src");
5713 LOGE("fail to get typefind src pad.\n");
5717 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5718 gboolean async = FALSE;
5719 LOGE("failed to autoplug %s\n", player->type);
5721 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5723 if (async && player->msg_posted == FALSE)
5724 __mmplayer_handle_missed_plugin(player);
5730 gst_object_unref(GST_OBJECT(pad));
5738 __mmplayer_gst_make_decodebin(mm_player_t* player)
5740 GstElement *decodebin = NULL;
5744 /* create decodebin */
5745 decodebin = gst_element_factory_make("decodebin", NULL);
5748 LOGE("fail to create decodebin\n");
5752 /* raw pad handling signal */
5753 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5754 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5756 /* no-more-pad pad handling signal */
5757 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5758 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5760 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5761 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5763 /* This signal is emitted when a pad for which there is no further possible
5764 decoding is added to the decodebin.*/
5765 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5766 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5768 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5769 before looking for any elements that can handle that stream.*/
5770 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5771 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5773 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5774 before looking for any elements that can handle that stream.*/
5775 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5776 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5778 /* This signal is emitted once decodebin has finished decoding all the data.*/
5779 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5780 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5782 /* This signal is emitted when a element is added to the bin.*/
5783 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5784 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5791 __mmplayer_gst_make_queue2(mm_player_t *player)
5793 GstElement* queue2 = NULL;
5794 gint64 dur_bytes = 0L;
5795 guint max_buffer_size_bytes = 0;
5796 MMPlayerGstElement *mainbin = NULL;
5797 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5800 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5802 mainbin = player->pipeline->mainbin;
5804 queue2 = gst_element_factory_make("queue2", "queue2");
5806 LOGE("failed to create buffering queue element");
5810 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5811 LOGE("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5813 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5815 if (dur_bytes > 0) {
5816 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
5817 type = MUXED_BUFFER_TYPE_FILE;
5819 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5820 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5826 /* NOTE : in case of ts streaming, player cannot get the correct duration info *
5827 * skip the pull mode(file or ring buffering) setting. */
5828 if (!g_strrstr(player->type, "video/mpegts")) {
5829 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
5830 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
5832 __mm_player_streaming_set_queue2(player->streamer,
5835 max_buffer_size_bytes,
5836 player->ini.http_buffering_time,
5837 1.0, /* no meaning */
5838 player->ini.http_buffering_limit, /* no meaning */
5840 player->http_file_buffering_path,
5841 (guint64)dur_bytes);
5848 __mmplayer_gst_create_decoder(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
5850 MMPlayerGstElement* mainbin = NULL;
5851 GstElement* decodebin = NULL;
5852 GstElement* queue2 = NULL;
5853 GstPad* sinkpad = NULL;
5854 GstPad* qsrcpad = NULL;
5855 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
5858 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
5860 mainbin = player->pipeline->mainbin;
5862 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
5864 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
5865 LOGW("need to check: muxed buffer is not null");
5868 queue2 = __mmplayer_gst_make_queue2(player);
5870 LOGE("failed to make queue2");
5874 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
5875 LOGE("failed to add buffering queue");
5879 sinkpad = gst_element_get_static_pad(queue2, "sink");
5880 qsrcpad = gst_element_get_static_pad(queue2, "src");
5882 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
5883 LOGE("failed to link [%s:%s]-[%s:%s]",
5884 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5888 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
5889 LOGE("failed to sync queue2 state with parent");
5893 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
5894 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
5898 gst_object_unref(GST_OBJECT(sinkpad));
5902 /* create decodebin */
5903 decodebin = __mmplayer_gst_make_decodebin(player);
5905 LOGE("failed to make decodebin");
5909 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
5910 LOGE("failed to add decodebin\n");
5914 /* to force caps on the decodebin element and avoid reparsing stuff by
5915 * typefind. It also avoids a deadlock in the way typefind activates pads in
5916 * the state change */
5917 g_object_set(decodebin, "sink-caps", caps, NULL);
5919 sinkpad = gst_element_get_static_pad(decodebin, "sink");
5921 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
5922 LOGE("failed to link [%s:%s]-[%s:%s]",
5923 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5927 gst_object_unref(GST_OBJECT(sinkpad));
5930 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
5931 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
5933 /* set decodebin property about buffer in streaming playback. *
5934 * in case of HLS/DASH, it does not need to have big buffer *
5935 * because it is kind of adaptive streaming. */
5936 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
5937 gdouble high_percent = 0.0;
5939 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
5940 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
5942 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
5943 GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
5945 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
5946 "high-percent", (gint)high_percent,
5947 "low-percent", (gint)DEFAULT_BUFFER_LOW_PERCENT,
5948 "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
5949 "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
5950 "max-size-buffers", 0, NULL); // disable or automatic
5953 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
5954 LOGE("failed to sync decodebin state with parent\n");
5965 gst_object_unref(GST_OBJECT(sinkpad));
5968 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
5969 * You need to explicitly set elements to the NULL state before
5970 * dropping the final reference, to allow them to clean up.
5972 gst_element_set_state(queue2, GST_STATE_NULL);
5974 /* And, it still has a parent "player".
5975 * You need to let the parent manage the object instead of unreffing the object directly.
5977 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
5978 gst_object_unref(queue2);
5983 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
5984 * You need to explicitly set elements to the NULL state before
5985 * dropping the final reference, to allow them to clean up.
5987 gst_element_set_state(decodebin, GST_STATE_NULL);
5989 /* And, it still has a parent "player".
5990 * You need to let the parent manage the object instead of unreffing the object directly.
5993 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
5994 gst_object_unref(decodebin);
6002 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
6006 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6007 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6009 LOGD("class : %s, mime : %s \n", factory_class, mime);
6011 /* add missing plugin */
6012 /* NOTE : msl should check missing plugin for image mime type.
6013 * Some motion jpeg clips can have playable audio track.
6014 * So, msl have to play audio after displaying popup written video format not supported.
6016 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6017 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6018 LOGD("not found demuxer\n");
6019 player->not_found_demuxer = TRUE;
6020 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6026 if (!g_strrstr(factory_class, "Demuxer")) {
6027 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6028 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
6029 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6031 /* check that clip have multi tracks or not */
6032 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6033 LOGD("video plugin is already linked\n");
6035 LOGW("add VIDEO to missing plugin\n");
6036 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6037 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6039 } else if (g_str_has_prefix(mime, "audio")) {
6040 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6041 LOGD("audio plugin is already linked\n");
6043 LOGW("add AUDIO to missing plugin\n");
6044 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6045 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6053 return MM_ERROR_NONE;
6058 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6060 mm_player_t* player = (mm_player_t*)data;
6064 MMPLAYER_RETURN_IF_FAIL(player);
6066 /* remove fakesink. */
6067 if (!__mmplayer_gst_remove_fakesink(player,
6068 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6069 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6070 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6071 * source element are not same. To overcome this situation, this function will called
6072 * several places and several times. Therefore, this is not an error case.
6077 LOGD("[handle: %p] pipeline has completely constructed", player);
6079 if ((player->ini.async_start) &&
6080 (player->msg_posted == FALSE) &&
6081 (player->cmd >= MMPLAYER_COMMAND_START))
6082 __mmplayer_handle_missed_plugin(player);
6084 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6088 __mmplayer_check_profile(void)
6091 static int profile_tv = -1;
6093 if (__builtin_expect(profile_tv != -1, 1))
6096 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6097 switch (*profileName) {
6112 __mmplayer_get_next_uri(mm_player_t *player)
6114 MMPlayerParseProfile profile;
6116 guint num_of_list = 0;
6119 num_of_list = g_list_length(player->uri_info.uri_list);
6120 uri_idx = player->uri_info.uri_idx;
6122 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6123 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6124 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6126 LOGW("next uri does not exist");
6130 if (__mmplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
6131 LOGE("failed to parse profile");
6135 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6136 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6137 LOGW("uri type is not supported(%d)", profile.uri_type);
6141 LOGD("success to find next uri %d", uri_idx);
6145 if (uri_idx == num_of_list) {
6146 LOGE("failed to find next uri");
6150 player->uri_info.uri_idx = uri_idx;
6151 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6153 if (mm_attrs_commit_all(player->attrs)) {
6154 LOGE("failed to commit");
6158 SECURE_LOGD("next playback uri: %s", uri);
6163 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6165 #define REPEAT_COUNT_INFINITELY -1
6166 #define REPEAT_COUNT_MIN 2
6168 MMHandleType attrs = 0;
6172 guint num_of_list = 0;
6173 int profile_tv = -1;
6177 LOGD("checking for gapless play option");
6179 if (player->pipeline->textbin) {
6180 LOGE("subtitle path is enabled. gapless play is not supported.\n");
6184 attrs = MMPLAYER_GET_ATTRS(player);
6186 LOGE("fail to get attributes.\n");
6190 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6192 /* gapless playback is not supported in case of video at TV profile. */
6193 profile_tv = __mmplayer_check_profile();
6194 if (profile_tv && video) {
6195 LOGW("not support video gapless playback");
6199 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6200 LOGE("failed to get play count");
6202 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6203 LOGE("failed to get gapless mode");
6205 /* check repeat count in case of audio */
6207 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6208 LOGW("gapless is disabled");
6212 num_of_list = g_list_length(player->uri_info.uri_list);
6214 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6216 if (num_of_list == 0) {
6217 /* audio looping path */
6218 if (count >= REPEAT_COUNT_MIN) {
6219 /* decrease play count */
6220 /* we succeeded to rewind. update play count and then wait for next EOS */
6223 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6225 /* commit attribute */
6226 if (mm_attrs_commit_all(attrs))
6227 LOGE("failed to commit attribute");
6228 } else if (count != REPEAT_COUNT_INFINITELY) {
6229 LOGD("there is no next uri and no repeat");
6233 LOGD("looping cnt %d", count);
6235 /* gapless playback path */
6236 if (!__mmplayer_get_next_uri(player)) {
6237 LOGE("failed to get next uri");
6245 LOGE("unable to play gapless path. EOS will be posted soon");
6250 __mmplayer_initialize_gapless_play(mm_player_t *player)
6256 player->smooth_streaming = FALSE;
6257 player->videodec_linked = 0;
6258 player->audiodec_linked = 0;
6259 player->textsink_linked = 0;
6260 player->is_external_subtitle_present = FALSE;
6261 player->is_external_subtitle_added_now = FALSE;
6262 player->not_supported_codec = MISSING_PLUGIN_NONE;
6263 player->can_support_codec = FOUND_PLUGIN_NONE;
6264 player->pending_seek.is_pending = FALSE;
6265 player->pending_seek.pos = 0;
6266 player->msg_posted = FALSE;
6267 player->has_many_types = FALSE;
6268 player->no_more_pad = FALSE;
6269 player->not_found_demuxer = 0;
6270 player->seek_state = MMPLAYER_SEEK_NONE;
6271 player->is_subtitle_force_drop = FALSE;
6272 player->play_subtitle = FALSE;
6273 player->adjust_subtitle_pos = 0;
6275 player->total_bitrate = 0;
6276 player->total_maximum_bitrate = 0;
6278 __mmplayer_track_initialize(player);
6279 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6281 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6282 player->bitrate[i] = 0;
6283 player->maximum_bitrate[i] = 0;
6286 if (player->v_stream_caps) {
6287 gst_caps_unref(player->v_stream_caps);
6288 player->v_stream_caps = NULL;
6291 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6293 /* clean found parsers */
6294 if (player->parsers) {
6295 GList *parsers = player->parsers;
6296 for (; parsers; parsers = g_list_next(parsers)) {
6297 gchar *name = parsers->data;
6298 MMPLAYER_FREEIF(name);
6300 g_list_free(player->parsers);
6301 player->parsers = NULL;
6304 /* clean found audio decoders */
6305 if (player->audio_decoders) {
6306 GList *a_dec = player->audio_decoders;
6307 for (; a_dec; a_dec = g_list_next(a_dec)) {
6308 gchar *name = a_dec->data;
6309 MMPLAYER_FREEIF(name);
6311 g_list_free(player->audio_decoders);
6312 player->audio_decoders = NULL;
6319 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6321 MMPlayerGstElement *mainbin = NULL;
6322 MMMessageParamType msg_param = {0,};
6323 GstElement *element = NULL;
6324 MMHandleType attrs = 0;
6326 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6330 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6331 LOGE("player is not initialized");
6335 mainbin = player->pipeline->mainbin;
6336 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6338 attrs = MMPLAYER_GET_ATTRS(player);
6340 LOGE("fail to get attributes");
6344 /* Initialize Player values */
6345 __mmplayer_initialize_gapless_play(player);
6347 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6349 if (__mmplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6350 LOGE("failed to parse profile");
6351 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6355 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6356 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6357 LOGE("dash or hls is not supportable");
6358 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6362 element = __mmplayer_gst_create_source(player);
6364 LOGE("no source element was created");
6368 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6369 LOGE("failed to add source element to pipeline");
6370 gst_object_unref(GST_OBJECT(element));
6375 /* take source element */
6376 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6377 mainbin[MMPLAYER_M_SRC].gst = element;
6381 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6382 if (player->streamer == NULL) {
6383 player->streamer = __mm_player_streaming_create();
6384 __mm_player_streaming_initialize(player->streamer);
6387 elem_idx = MMPLAYER_M_TYPEFIND;
6388 element = gst_element_factory_make("typefind", "typefinder");
6389 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6390 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6392 elem_idx = MMPLAYER_M_AUTOPLUG;
6393 element = __mmplayer_gst_make_decodebin(player);
6396 /* check autoplug element is OK */
6398 LOGE("can not create element(%d)", elem_idx);
6402 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6403 LOGE("failed to add sinkbin to pipeline");
6404 gst_object_unref(GST_OBJECT(element));
6409 mainbin[elem_idx].id = elem_idx;
6410 mainbin[elem_idx].gst = element;
6412 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6413 LOGE("Failed to link src - autoplug(or typefind)");
6417 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6418 LOGE("Failed to change state of src element");
6422 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6423 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6424 LOGE("Failed to change state of decodebin");
6428 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6429 LOGE("Failed to change state of src element");
6434 player->gapless.stream_changed = TRUE;
6435 player->gapless.running = TRUE;
6441 MMPLAYER_PLAYBACK_UNLOCK(player);
6443 if (!player->msg_posted) {
6444 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6445 player->msg_posted = TRUE;
6452 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6454 mm_player_selector_t *selector = &player->selector[type];
6455 MMPlayerGstElement *sinkbin = NULL;
6456 enum MainElementID selectorId = MMPLAYER_M_NUM;
6457 enum MainElementID sinkId = MMPLAYER_M_NUM;
6458 GstPad *srcpad = NULL;
6459 GstPad *sinkpad = NULL;
6460 gboolean send_notice = FALSE;
6463 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6465 LOGD("type %d", type);
6468 case MM_PLAYER_TRACK_TYPE_AUDIO:
6469 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6470 sinkId = MMPLAYER_A_BIN;
6471 sinkbin = player->pipeline->audiobin;
6473 case MM_PLAYER_TRACK_TYPE_VIDEO:
6474 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6475 sinkId = MMPLAYER_V_BIN;
6476 sinkbin = player->pipeline->videobin;
6479 case MM_PLAYER_TRACK_TYPE_TEXT:
6480 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6481 sinkId = MMPLAYER_T_BIN;
6482 sinkbin = player->pipeline->textbin;
6485 LOGE("requested type is not supportable");
6490 if (player->pipeline->mainbin[selectorId].gst) {
6493 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6495 if (selector->event_probe_id != 0)
6496 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6497 selector->event_probe_id = 0;
6499 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6500 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6502 if (srcpad && sinkpad) {
6503 /* after getting drained signal there is no data flows, so no need to do pad_block */
6504 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6505 gst_pad_unlink(srcpad, sinkpad);
6507 /* send custom event to sink pad to handle it at video sink */
6509 LOGD("send custom event to sinkpad");
6510 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6511 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6512 gst_pad_send_event(sinkpad, event);
6516 gst_object_unref(sinkpad);
6519 gst_object_unref(srcpad);
6522 LOGD("selector release");
6524 /* release and unref requests pad from the selector */
6525 for (n = 0; n < selector->channels->len; n++) {
6526 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6527 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6529 g_ptr_array_set_size(selector->channels, 0);
6531 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6532 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6534 player->pipeline->mainbin[selectorId].gst = NULL;
6542 __mmplayer_deactivate_old_path(mm_player_t *player)
6545 MMPLAYER_RETURN_IF_FAIL(player);
6547 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6548 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6549 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6550 LOGE("deactivate selector error");
6554 __mmplayer_track_destroy(player);
6555 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6557 if (player->streamer) {
6558 __mm_player_streaming_deinitialize(player->streamer);
6559 __mm_player_streaming_destroy(player->streamer);
6560 player->streamer = NULL;
6563 MMPLAYER_PLAYBACK_LOCK(player);
6564 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6571 if (!player->msg_posted) {
6572 MMMessageParamType msg = {0,};
6575 msg.code = MM_ERROR_PLAYER_INTERNAL;
6576 LOGE("gapless_uri_play> deactivate error");
6578 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6579 player->msg_posted = TRUE;
6584 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
6586 int result = MM_ERROR_NONE;
6587 mm_player_t* player = (mm_player_t*) hplayer;
6590 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6593 player->http_file_buffering_path = (gchar*)file_path;
6594 LOGD("temp file path: %s\n", player->http_file_buffering_path);
6600 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
6602 int result = MM_ERROR_NONE;
6603 mm_player_t* player = (mm_player_t*) hplayer;
6606 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6608 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6609 if (mm_attrs_commit_all(player->attrs)) {
6610 LOGE("failed to commit the original uri.\n");
6611 result = MM_ERROR_PLAYER_INTERNAL;
6613 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6614 LOGE("failed to add the original uri in the uri list.\n");
6621 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
6623 mm_player_t* player = (mm_player_t*) hplayer;
6624 guint num_of_list = 0;
6628 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6629 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6631 if (player->pipeline && player->pipeline->textbin) {
6632 LOGE("subtitle path is enabled.\n");
6633 return MM_ERROR_PLAYER_INVALID_STATE;
6636 num_of_list = g_list_length(player->uri_info.uri_list);
6638 if (is_first_path == TRUE) {
6639 if (num_of_list == 0) {
6640 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6641 LOGD("add original path : %s", uri);
6643 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6644 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6646 LOGD("change original path : %s", uri);
6649 MMHandleType attrs = 0;
6650 attrs = MMPLAYER_GET_ATTRS(player);
6652 if (num_of_list == 0) {
6653 char *original_uri = NULL;
6656 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6658 if (!original_uri) {
6659 LOGE("there is no original uri.");
6660 return MM_ERROR_PLAYER_INVALID_STATE;
6663 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6664 player->uri_info.uri_idx = 0;
6666 LOGD("add original path at first : %s", original_uri);
6670 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6671 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6675 return MM_ERROR_NONE;
6678 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
6680 mm_player_t* player = (mm_player_t*) hplayer;
6681 char *next_uri = NULL;
6682 guint num_of_list = 0;
6685 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6687 num_of_list = g_list_length(player->uri_info.uri_list);
6689 if (num_of_list > 0) {
6690 gint uri_idx = player->uri_info.uri_idx;
6692 if (uri_idx < num_of_list-1)
6697 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6698 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
6700 *uri = g_strdup(next_uri);
6704 return MM_ERROR_NONE;
6708 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
6709 GstCaps *caps, gpointer data)
6711 mm_player_t* player = (mm_player_t*)data;
6712 const gchar* klass = NULL;
6713 const gchar* mime = NULL;
6714 gchar* caps_str = NULL;
6716 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6717 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6718 caps_str = gst_caps_to_string(caps);
6720 LOGW("unknown type of caps : %s from %s",
6721 caps_str, GST_ELEMENT_NAME(elem));
6723 MMPLAYER_FREEIF(caps_str);
6725 /* There is no available codec. */
6726 __mmplayer_check_not_supported_codec(player, klass, mime);
6730 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
6731 GstCaps * caps, gpointer data)
6733 mm_player_t* player = (mm_player_t*)data;
6734 const char* mime = NULL;
6735 gboolean ret = TRUE;
6737 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6738 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6740 if (g_str_has_prefix(mime, "audio")) {
6741 GstStructure* caps_structure = NULL;
6742 gint samplerate = 0;
6744 gchar *caps_str = NULL;
6746 caps_structure = gst_caps_get_structure(caps, 0);
6747 gst_structure_get_int(caps_structure, "rate", &samplerate);
6748 gst_structure_get_int(caps_structure, "channels", &channels);
6750 if ((channels > 0 && samplerate == 0)) {
6751 LOGD("exclude audio...");
6755 caps_str = gst_caps_to_string(caps);
6756 /* set it directly because not sent by TAG */
6757 if (g_strrstr(caps_str, "mobile-xmf"))
6758 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6759 MMPLAYER_FREEIF(caps_str);
6760 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6761 MMMessageParamType msg_param;
6762 memset(&msg_param, 0, sizeof(MMMessageParamType));
6763 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6764 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6765 LOGD("video file is not supported on this device");
6767 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6768 LOGD("already video linked");
6771 LOGD("found new stream");
6778 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
6780 int ret = MM_ERROR_NONE;
6782 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6784 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6785 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6787 LOGD("audio codec type: %d", codec_type);
6788 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6789 /* sw codec will be skipped */
6790 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6791 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6792 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6793 ret = MM_ERROR_PLAYER_INTERNAL;
6797 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6798 /* hw codec will be skipped */
6799 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6800 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6801 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6802 ret = MM_ERROR_PLAYER_INTERNAL;
6807 /* set stream information */
6808 if (!player->audiodec_linked)
6809 __mmplayer_set_audio_attrs(player, caps);
6811 /* update codec info */
6812 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6813 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6814 player->audiodec_linked = 1;
6816 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6818 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6820 LOGD("video codec type: %d", codec_type);
6821 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6822 /* sw codec is skipped */
6823 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
6824 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
6825 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
6826 ret = MM_ERROR_PLAYER_INTERNAL;
6830 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6831 /* hw codec is skipped */
6832 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
6833 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
6834 ret = MM_ERROR_PLAYER_INTERNAL;
6839 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
6840 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
6842 /* mark video decoder for acquire */
6843 if (player->video_decoder_resource == NULL) {
6844 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
6845 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
6846 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
6847 &player->video_decoder_resource)
6848 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6849 LOGE("could not mark video_decoder resource for acquire");
6850 ret = MM_ERROR_PLAYER_INTERNAL;
6854 LOGW("video decoder resource is already acquired, skip it.");
6855 ret = MM_ERROR_PLAYER_INTERNAL;
6859 player->interrupted_by_resource = FALSE;
6860 /* acquire resources for video playing */
6861 if (mm_resource_manager_commit(player->resource_manager)
6862 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6863 LOGE("could not acquire resources for video decoding\n");
6864 ret = MM_ERROR_PLAYER_INTERNAL;
6869 /* update codec info */
6870 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
6871 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
6872 player->videodec_linked = 1;
6880 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
6881 GstCaps* caps, GstElementFactory* factory, gpointer data)
6883 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
6884 We are defining our own and will be removed when it actually exposed */
6886 GST_AUTOPLUG_SELECT_TRY,
6887 GST_AUTOPLUG_SELECT_EXPOSE,
6888 GST_AUTOPLUG_SELECT_SKIP
6889 } GstAutoplugSelectResult;
6891 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
6892 mm_player_t* player = (mm_player_t*)data;
6894 gchar* factory_name = NULL;
6895 gchar* caps_str = NULL;
6896 const gchar* klass = NULL;
6899 factory_name = GST_OBJECT_NAME(factory);
6900 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
6901 caps_str = gst_caps_to_string(caps);
6903 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
6905 /* store type string */
6906 if (player->type == NULL) {
6907 player->type = gst_caps_to_string(caps);
6908 __mmplayer_update_content_type_info(player);
6911 /* filtering exclude keyword */
6912 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
6913 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
6914 LOGW("skipping [%s] by exculde keyword [%s]",
6915 factory_name, player->ini.exclude_element_keyword[idx]);
6917 result = GST_AUTOPLUG_SELECT_SKIP;
6922 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
6923 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
6924 LOGW("skipping [%s] by unsupported codec keyword [%s]",
6925 factory_name, player->ini.unsupported_codec_keyword[idx]);
6926 result = GST_AUTOPLUG_SELECT_SKIP;
6931 /* exclude webm format */
6932 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
6933 * because webm format is not supportable.
6934 * If webm is disabled in "autoplug-continue", there is no state change
6935 * failure or error because the decodebin will expose the pad directly.
6936 * It make MSL invoke _prepare_async_callback.
6937 * So, we need to disable webm format in "autoplug-select" */
6938 if (caps_str && strstr(caps_str, "webm")) {
6939 LOGW("webm is not supported");
6940 result = GST_AUTOPLUG_SELECT_SKIP;
6944 /* check factory class for filtering */
6945 /* NOTE : msl don't need to use image plugins.
6946 * So, those plugins should be skipped for error handling.
6948 if (g_strrstr(klass, "Codec/Decoder/Image")) {
6949 LOGD("skipping [%s] by not required\n", factory_name);
6950 result = GST_AUTOPLUG_SELECT_SKIP;
6954 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
6955 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
6956 // TO CHECK : subtitle if needed, add subparse exception.
6957 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
6958 result = GST_AUTOPLUG_SELECT_SKIP;
6962 if (g_strrstr(factory_name, "mpegpsdemux")) {
6963 LOGD("skipping PS container - not support\n");
6964 result = GST_AUTOPLUG_SELECT_SKIP;
6968 if (g_strrstr(factory_name, "mssdemux"))
6969 player->smooth_streaming = TRUE;
6971 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
6972 (g_strrstr(klass, "Codec/Decoder/Video"))) {
6975 GstStructure *str = NULL;
6976 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
6978 /* don't make video because of not required */
6979 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
6980 (!player->set_mode.media_packet_video_stream)) {
6981 LOGD("no need video decoding, expose pad");
6982 result = GST_AUTOPLUG_SELECT_EXPOSE;
6986 /* get w/h for omx state-tune */
6987 /* FIXME: deprecated? */
6988 str = gst_caps_get_structure(caps, 0);
6989 gst_structure_get_int(str, "width", &width);
6992 if (player->v_stream_caps) {
6993 gst_caps_unref(player->v_stream_caps);
6994 player->v_stream_caps = NULL;
6997 player->v_stream_caps = gst_caps_copy(caps);
6998 LOGD("take caps for video state tune");
6999 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7003 if (g_strrstr(klass, "Codec/Decoder")) {
7004 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
7005 LOGD("skipping %s codec", factory_name);
7006 result = GST_AUTOPLUG_SELECT_SKIP;
7012 MMPLAYER_FREEIF(caps_str);
7018 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
7021 //mm_player_t* player = (mm_player_t*)data;
7022 GstCaps* caps = NULL;
7024 LOGD("[Decodebin2] pad-removed signal\n");
7026 caps = gst_pad_query_caps(new_pad, NULL);
7028 gchar* caps_str = NULL;
7029 caps_str = gst_caps_to_string(caps);
7031 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7033 MMPLAYER_FREEIF(caps_str);
7034 gst_caps_unref(caps);
7039 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7041 mm_player_t* player = (mm_player_t*)data;
7042 GstIterator *iter = NULL;
7043 GValue item = { 0, };
7045 gboolean done = FALSE;
7046 gboolean is_all_drained = TRUE;
7049 MMPLAYER_RETURN_IF_FAIL(player);
7051 LOGD("__mmplayer_gst_decode_drained");
7053 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7054 LOGW("Fail to get cmd lock");
7058 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7059 !__mmplayer_verify_gapless_play_path(player)) {
7060 LOGD("decoding is finished.");
7061 __mmplayer_reset_gapless_state(player);
7062 MMPLAYER_CMD_UNLOCK(player);
7066 player->gapless.reconfigure = TRUE;
7068 /* check decodebin src pads whether they received EOS or not */
7069 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7072 switch (gst_iterator_next(iter, &item)) {
7073 case GST_ITERATOR_OK:
7074 pad = g_value_get_object(&item);
7075 if (pad && !GST_PAD_IS_EOS(pad)) {
7076 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7077 is_all_drained = FALSE;
7080 g_value_reset(&item);
7082 case GST_ITERATOR_RESYNC:
7083 gst_iterator_resync(iter);
7085 case GST_ITERATOR_ERROR:
7086 case GST_ITERATOR_DONE:
7091 g_value_unset(&item);
7092 gst_iterator_free(iter);
7094 if (!is_all_drained) {
7095 LOGD("Wait util the all pads get EOS.");
7096 MMPLAYER_CMD_UNLOCK(player);
7101 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7102 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7104 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7105 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7106 __mmplayer_deactivate_old_path(player);
7107 MMPLAYER_CMD_UNLOCK(player);
7113 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7115 mm_player_t* player = (mm_player_t*)data;
7116 const gchar* klass = NULL;
7117 gchar* factory_name = NULL;
7119 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7120 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7122 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
7124 if (__mmplayer_add_dump_buffer_probe(player, element))
7125 LOGD("add buffer probe");
7128 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7129 gchar* selected = NULL;
7130 selected = g_strdup(GST_ELEMENT_NAME(element));
7131 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7135 if (g_strrstr(klass, "Parser")) {
7136 gchar* selected = NULL;
7138 selected = g_strdup(factory_name);
7139 player->parsers = g_list_append(player->parsers, selected);
7142 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7143 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7144 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7146 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7147 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7149 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7150 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7151 "max-video-width", player->adaptive_info.limit.width,
7152 "max-video-height", player->adaptive_info.limit.height, NULL);
7154 } else if (g_strrstr(klass, "Demuxer")) {
7155 //LOGD("plugged element is demuxer. take it");
7156 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7157 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7160 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7161 int surface_type = 0;
7163 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7166 // to support trust-zone only
7167 if (g_strrstr(factory_name, "asfdemux")) {
7168 LOGD("set file-location %s\n", player->profile.uri);
7169 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7170 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7171 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
7172 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7173 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7174 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7175 (__mmplayer_is_only_mp3_type(player->type))) {
7176 LOGD("[mpegaudioparse] set streaming pull mode.");
7177 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7179 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7180 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7183 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7184 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7185 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7187 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7188 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7190 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7191 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7192 (MMPLAYER_IS_DASH_STREAMING(player))) {
7193 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7194 __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time, 1.0, player->ini.http_buffering_limit);
7195 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7204 __mmplayer_release_misc(mm_player_t* player)
7207 bool cur_mode = player->set_mode.rich_audio;
7210 MMPLAYER_RETURN_IF_FAIL(player);
7212 player->video_stream_cb = NULL;
7213 player->video_stream_cb_user_param = NULL;
7214 player->video_stream_prerolled = FALSE;
7216 player->audio_stream_render_cb = NULL;
7217 player->audio_stream_cb_user_param = NULL;
7218 player->audio_stream_sink_sync = false;
7220 player->video_stream_changed_cb = NULL;
7221 player->video_stream_changed_cb_user_param = NULL;
7223 player->audio_stream_changed_cb = NULL;
7224 player->audio_stream_changed_cb_user_param = NULL;
7226 player->sent_bos = FALSE;
7227 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7229 player->seek_state = MMPLAYER_SEEK_NONE;
7231 player->total_bitrate = 0;
7232 player->total_maximum_bitrate = 0;
7234 player->not_found_demuxer = 0;
7236 player->last_position = 0;
7237 player->duration = 0;
7238 player->http_content_size = 0;
7239 player->not_supported_codec = MISSING_PLUGIN_NONE;
7240 player->can_support_codec = FOUND_PLUGIN_NONE;
7241 player->pending_seek.is_pending = FALSE;
7242 player->pending_seek.pos = 0;
7243 player->msg_posted = FALSE;
7244 player->has_many_types = FALSE;
7245 player->is_subtitle_force_drop = FALSE;
7246 player->play_subtitle = FALSE;
7247 player->adjust_subtitle_pos = 0;
7248 player->last_multiwin_status = FALSE;
7249 player->has_closed_caption = FALSE;
7250 player->set_mode.media_packet_video_stream = false;
7251 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7252 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7254 player->set_mode.rich_audio = cur_mode;
7256 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7257 player->bitrate[i] = 0;
7258 player->maximum_bitrate[i] = 0;
7261 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7263 /* remove media stream cb(appsrc cb) */
7264 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7265 player->media_stream_buffer_status_cb[i] = NULL;
7266 player->media_stream_seek_data_cb[i] = NULL;
7267 player->buffer_cb_user_param[i] = NULL;
7268 player->seek_cb_user_param[i] = NULL;
7270 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7272 /* free memory related to audio effect */
7273 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7275 if (player->adaptive_info.var_list) {
7276 g_list_free_full(player->adaptive_info.var_list, g_free);
7277 player->adaptive_info.var_list = NULL;
7280 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7281 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7282 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7284 /* Reset video360 settings to their defaults in case if the pipeline is to be
7287 player->video360_metadata.is_spherical = -1;
7288 player->is_openal_plugin_used = FALSE;
7290 player->is_content_spherical = FALSE;
7291 player->is_video360_enabled = TRUE;
7292 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7293 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7294 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7295 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7296 player->video360_zoom = 1.0f;
7297 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7298 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7300 player->sound.rg_enable = false;
7302 __mmplayer_initialize_video_roi(player);
7307 __mmplayer_release_misc_post(mm_player_t* player)
7309 char *original_uri = NULL;
7312 /* player->pipeline is already released before. */
7314 MMPLAYER_RETURN_IF_FAIL(player);
7316 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7318 /* clean found parsers */
7319 if (player->parsers) {
7320 GList *parsers = player->parsers;
7321 for (; parsers; parsers = g_list_next(parsers)) {
7322 gchar *name = parsers->data;
7323 MMPLAYER_FREEIF(name);
7325 g_list_free(player->parsers);
7326 player->parsers = NULL;
7329 /* clean found audio decoders */
7330 if (player->audio_decoders) {
7331 GList *a_dec = player->audio_decoders;
7332 for (; a_dec; a_dec = g_list_next(a_dec)) {
7333 gchar *name = a_dec->data;
7334 MMPLAYER_FREEIF(name);
7336 g_list_free(player->audio_decoders);
7337 player->audio_decoders = NULL;
7340 /* clean the uri list except original uri */
7341 if (player->uri_info.uri_list) {
7342 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7344 if (player->attrs) {
7345 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7346 LOGD("restore original uri = %s\n", original_uri);
7348 if (mm_attrs_commit_all(player->attrs))
7349 LOGE("failed to commit the original uri.\n");
7352 GList *uri_list = player->uri_info.uri_list;
7353 for (; uri_list; uri_list = g_list_next(uri_list)) {
7354 gchar *uri = uri_list->data;
7355 MMPLAYER_FREEIF(uri);
7357 g_list_free(player->uri_info.uri_list);
7358 player->uri_info.uri_list = NULL;
7361 /* clear the audio stream buffer list */
7362 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7364 /* clear the video stream bo list */
7365 __mmplayer_video_stream_destroy_bo_list(player);
7366 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7368 if (player->profile.input_mem.buf) {
7369 free(player->profile.input_mem.buf);
7370 player->profile.input_mem.buf = NULL;
7372 player->profile.input_mem.len = 0;
7373 player->profile.input_mem.offset = 0;
7375 player->uri_info.uri_idx = 0;
7380 __mmplayer_check_subtitle(mm_player_t* player)
7382 MMHandleType attrs = 0;
7383 char *subtitle_uri = NULL;
7387 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7389 /* get subtitle attribute */
7390 attrs = MMPLAYER_GET_ATTRS(player);
7394 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7395 if (!subtitle_uri || !strlen(subtitle_uri))
7398 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7399 player->is_external_subtitle_present = TRUE;
7407 __mmplayer_cancel_eos_timer(mm_player_t* player)
7409 MMPLAYER_RETURN_IF_FAIL(player);
7411 if (player->eos_timer) {
7412 LOGD("cancel eos timer");
7413 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7414 player->eos_timer = 0;
7421 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
7425 MMPLAYER_RETURN_IF_FAIL(player);
7426 MMPLAYER_RETURN_IF_FAIL(sink);
7428 player->sink_elements =
7429 g_list_append(player->sink_elements, sink);
7435 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
7439 MMPLAYER_RETURN_IF_FAIL(player);
7440 MMPLAYER_RETURN_IF_FAIL(sink);
7442 player->sink_elements =
7443 g_list_remove(player->sink_elements, sink);
7449 __mmplayer_add_signal_connection(mm_player_t* player, GObject* object,
7450 MMPlayerSignalType type, const gchar* signal, GCallback cb_funct, gpointer u_data)
7452 MMPlayerSignalItem* item = NULL;
7455 MMPLAYER_RETURN_IF_FAIL(player);
7457 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7458 LOGE("invalid signal type [%d]", type);
7462 item = (MMPlayerSignalItem*)g_malloc(sizeof(MMPlayerSignalItem));
7464 LOGE("cannot connect signal [%s]", signal);
7469 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7470 player->signals[type] = g_list_append(player->signals[type], item);
7476 /* NOTE : be careful with calling this api. please refer to below glib comment
7477 * glib comment : Note that there is a bug in GObject that makes this function much
7478 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7479 * will no longer be called, but, the signal handler is not currently disconnected.
7480 * If the instance is itself being freed at the same time than this doesn't matter,
7481 * since the signal will automatically be removed, but if instance persists,
7482 * then the signal handler will leak. You should not remove the signal yourself
7483 * because in a future versions of GObject, the handler will automatically be
7486 * It's possible to work around this problem in a way that will continue to work
7487 * with future versions of GObject by checking that the signal handler is still
7488 * connected before disconnected it:
7490 * if (g_signal_handler_is_connected(instance, id))
7491 * g_signal_handler_disconnect(instance, id);
7494 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
7496 GList* sig_list = NULL;
7497 MMPlayerSignalItem* item = NULL;
7501 MMPLAYER_RETURN_IF_FAIL(player);
7503 LOGD("release signals type : %d", type);
7505 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7506 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7507 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7508 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7509 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7510 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7514 sig_list = player->signals[type];
7516 for (; sig_list; sig_list = sig_list->next) {
7517 item = sig_list->data;
7519 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7520 if (g_signal_handler_is_connected(item->obj, item->sig))
7521 g_signal_handler_disconnect(item->obj, item->sig);
7524 MMPLAYER_FREEIF(item);
7527 g_list_free(player->signals[type]);
7528 player->signals[type] = NULL;
7535 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7537 mm_player_t* player = 0;
7538 int prev_display_surface_type = 0;
7539 void *prev_display_overlay = NULL;
7543 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7544 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7546 player = MM_PLAYER_CAST(handle);
7548 /* check video sinkbin is created */
7549 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7550 LOGE("Videosink is already created");
7551 return MM_ERROR_NONE;
7554 LOGD("videosink element is not yet ready");
7556 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7557 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7559 return MM_ERROR_INVALID_ARGUMENT;
7562 /* load previous attributes */
7563 if (player->attrs) {
7564 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7565 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7566 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7567 if (prev_display_surface_type == surface_type) {
7568 LOGD("incoming display surface type is same as previous one, do nothing..");
7570 return MM_ERROR_NONE;
7573 LOGE("failed to load attributes");
7575 return MM_ERROR_PLAYER_INTERNAL;
7578 /* videobin is not created yet, so we just set attributes related to display surface */
7579 LOGD("store display attribute for given surface type(%d)", surface_type);
7580 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7581 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7582 if (mm_attrs_commit_all(player->attrs)) {
7583 LOGE("failed to commit attribute");
7585 return MM_ERROR_PLAYER_INTERNAL;
7589 return MM_ERROR_NONE;
7592 /* Note : if silent is true, then subtitle would not be displayed. :*/
7593 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7595 mm_player_t* player = (mm_player_t*) hplayer;
7599 /* check player handle */
7600 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7602 player->set_mode.subtitle_off = silent;
7604 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
7608 return MM_ERROR_NONE;
7611 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
7613 MMPlayerGstElement* mainbin = NULL;
7614 MMPlayerGstElement* textbin = NULL;
7615 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7616 GstState current_state = GST_STATE_VOID_PENDING;
7617 GstState element_state = GST_STATE_VOID_PENDING;
7618 GstState element_pending_state = GST_STATE_VOID_PENDING;
7620 GstEvent *event = NULL;
7621 int result = MM_ERROR_NONE;
7623 GstClock *curr_clock = NULL;
7624 GstClockTime base_time, start_time, curr_time;
7629 /* check player handle */
7630 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7632 player->pipeline->mainbin &&
7633 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7635 mainbin = player->pipeline->mainbin;
7636 textbin = player->pipeline->textbin;
7638 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7640 // sync clock with current pipeline
7641 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7642 curr_time = gst_clock_get_time(curr_clock);
7644 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7645 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7647 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7648 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7650 if (current_state > GST_STATE_READY) {
7651 // sync state with current pipeline
7652 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7653 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7654 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7656 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7657 if (GST_STATE_CHANGE_FAILURE == ret) {
7658 LOGE("fail to state change.\n");
7659 result = MM_ERROR_PLAYER_INTERNAL;
7663 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7664 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7667 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7668 gst_object_unref(curr_clock);
7671 // seek to current position
7672 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7673 result = MM_ERROR_PLAYER_INVALID_STATE;
7674 LOGE("gst_element_query_position failed, invalid state\n");
7678 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7679 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);
7681 __mmplayer_gst_send_event_to_sink(player, event);
7683 result = MM_ERROR_PLAYER_INTERNAL;
7684 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7688 /* sync state with current pipeline */
7689 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7690 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7691 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7693 return MM_ERROR_NONE;
7696 /* release text pipeline resource */
7697 player->textsink_linked = 0;
7699 /* release signal */
7700 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7702 /* release textbin with it's childs */
7703 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7704 MMPLAYER_FREEIF(player->pipeline->textbin);
7705 player->pipeline->textbin = NULL;
7707 /* release subtitle elem */
7708 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7709 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7715 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
7717 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7718 GstState current_state = GST_STATE_VOID_PENDING;
7720 MMHandleType attrs = 0;
7721 MMPlayerGstElement* mainbin = NULL;
7722 MMPlayerGstElement* textbin = NULL;
7724 gchar* subtitle_uri = NULL;
7725 int result = MM_ERROR_NONE;
7726 const gchar *charset = NULL;
7730 /* check player handle */
7731 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7733 player->pipeline->mainbin &&
7734 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7735 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7737 mainbin = player->pipeline->mainbin;
7738 textbin = player->pipeline->textbin;
7740 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7741 if (current_state < GST_STATE_READY) {
7742 result = MM_ERROR_PLAYER_INVALID_STATE;
7743 LOGE("Pipeline is not in proper state\n");
7747 attrs = MMPLAYER_GET_ATTRS(player);
7749 LOGE("cannot get content attribute\n");
7750 result = MM_ERROR_PLAYER_INTERNAL;
7754 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7755 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7756 LOGE("subtitle uri is not proper filepath\n");
7757 result = MM_ERROR_PLAYER_INVALID_URI;
7761 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7762 LOGE("failed to get storage info of subtitle path");
7763 result = MM_ERROR_PLAYER_INVALID_URI;
7767 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
7768 LOGD("new subtitle file path is [%s]\n", filepath);
7770 if (!strcmp(filepath, subtitle_uri)) {
7771 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
7774 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7775 if (mm_attrs_commit_all(player->attrs)) {
7776 LOGE("failed to commit.\n");
7781 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7782 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7783 player->subtitle_language_list = NULL;
7784 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7786 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7787 if (ret != GST_STATE_CHANGE_SUCCESS) {
7788 LOGE("failed to change state of textbin to READY");
7789 result = MM_ERROR_PLAYER_INTERNAL;
7793 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7794 if (ret != GST_STATE_CHANGE_SUCCESS) {
7795 LOGE("failed to change state of subparse to READY");
7796 result = MM_ERROR_PLAYER_INTERNAL;
7800 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7801 if (ret != GST_STATE_CHANGE_SUCCESS) {
7802 LOGE("failed to change state of filesrc to READY");
7803 result = MM_ERROR_PLAYER_INTERNAL;
7807 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7809 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7811 charset = util_get_charset(filepath);
7813 LOGD("detected charset is %s\n", charset);
7814 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7817 result = _mmplayer_sync_subtitle_pipeline(player);
7824 /* API to switch between external subtitles */
7825 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
7827 int result = MM_ERROR_NONE;
7828 mm_player_t* player = (mm_player_t*)hplayer;
7833 /* check player handle */
7834 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7836 /* filepath can be null in idle state */
7838 /* check file path */
7839 if ((path = strstr(filepath, "file://")))
7840 result = util_exist_file_path(path + 7);
7842 result = util_exist_file_path(filepath);
7844 if (result != MM_ERROR_NONE) {
7845 LOGE("invalid subtitle path 0x%X", result);
7846 return result; /* file not found or permission denied */
7850 if (!player->pipeline) {
7852 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7853 if (mm_attrs_commit_all(player->attrs)) {
7854 LOGE("failed to commit"); /* subtitle path will not be created */
7855 return MM_ERROR_PLAYER_INTERNAL;
7858 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7859 /* check filepath */
7860 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7862 if (!__mmplayer_check_subtitle(player)) {
7863 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7864 if (mm_attrs_commit_all(player->attrs)) {
7865 LOGE("failed to commit");
7866 return MM_ERROR_PLAYER_INTERNAL;
7869 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
7870 LOGE("fail to create text pipeline");
7871 return MM_ERROR_PLAYER_INTERNAL;
7874 result = _mmplayer_sync_subtitle_pipeline(player);
7876 result = __mmplayer_change_external_subtitle_language(player, filepath);
7879 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
7880 player->is_external_subtitle_added_now = TRUE;
7882 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7883 if (!player->subtitle_language_list) {
7884 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
7885 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
7886 LOGW("subtitle language list is not updated yet");
7888 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7896 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
7898 int result = MM_ERROR_NONE;
7899 gchar* change_pad_name = NULL;
7900 GstPad* sinkpad = NULL;
7901 MMPlayerGstElement* mainbin = NULL;
7902 enum MainElementID elem_idx = MMPLAYER_M_NUM;
7903 GstCaps* caps = NULL;
7904 gint total_track_num = 0;
7908 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
7909 MM_ERROR_PLAYER_NOT_INITIALIZED);
7911 LOGD("Change Track(%d) to %d\n", type, index);
7913 mainbin = player->pipeline->mainbin;
7915 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
7916 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
7917 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
7918 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
7920 /* Changing Video Track is not supported. */
7921 LOGE("Track Type Error\n");
7925 if (mainbin[elem_idx].gst == NULL) {
7926 result = MM_ERROR_PLAYER_NO_OP;
7927 LOGD("Req track doesn't exist\n");
7931 total_track_num = player->selector[type].total_track_num;
7932 if (total_track_num <= 0) {
7933 result = MM_ERROR_PLAYER_NO_OP;
7934 LOGD("Language list is not available \n");
7938 if ((index < 0) || (index >= total_track_num)) {
7939 result = MM_ERROR_INVALID_ARGUMENT;
7940 LOGD("Not a proper index : %d \n", index);
7944 /*To get the new pad from the selector*/
7945 change_pad_name = g_strdup_printf("sink_%u", index);
7946 if (change_pad_name == NULL) {
7947 result = MM_ERROR_PLAYER_INTERNAL;
7948 LOGD("Pad does not exists\n");
7952 LOGD("new active pad name: %s\n", change_pad_name);
7954 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
7955 if (sinkpad == NULL) {
7956 LOGD("sinkpad is NULL");
7957 result = MM_ERROR_PLAYER_INTERNAL;
7961 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
7962 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
7964 caps = gst_pad_get_current_caps(sinkpad);
7965 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
7968 gst_object_unref(sinkpad);
7970 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
7971 __mmplayer_set_audio_attrs(player, caps);
7975 MMPLAYER_FREEIF(change_pad_name);
7979 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
7981 int result = MM_ERROR_NONE;
7982 mm_player_t* player = NULL;
7983 MMPlayerGstElement* mainbin = NULL;
7985 gint current_active_index = 0;
7987 GstState current_state = GST_STATE_VOID_PENDING;
7988 GstEvent* event = NULL;
7993 player = (mm_player_t*)hplayer;
7994 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7996 if (!player->pipeline) {
7997 LOGE("Track %d pre setting -> %d\n", type, index);
7999 player->selector[type].active_pad_index = index;
8003 mainbin = player->pipeline->mainbin;
8005 current_active_index = player->selector[type].active_pad_index;
8007 /*If index is same as running index no need to change the pad*/
8008 if (current_active_index == index)
8011 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8012 result = MM_ERROR_PLAYER_INVALID_STATE;
8016 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8017 if (current_state < GST_STATE_PAUSED) {
8018 result = MM_ERROR_PLAYER_INVALID_STATE;
8019 LOGW("Pipeline not in porper state\n");
8023 result = __mmplayer_change_selector_pad(player, type, index);
8024 if (result != MM_ERROR_NONE) {
8025 LOGE("change selector pad error\n");
8029 player->selector[type].active_pad_index = index;
8031 if (current_state == GST_STATE_PLAYING) {
8032 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);
8034 __mmplayer_gst_send_event_to_sink(player, event);
8036 result = MM_ERROR_PLAYER_INTERNAL;
8045 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
8047 mm_player_t* player = (mm_player_t*) hplayer;
8051 /* check player handle */
8052 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8054 *silent = player->set_mode.subtitle_off;
8056 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
8060 return MM_ERROR_NONE;
8064 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8066 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8067 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8069 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8070 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8074 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8075 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8076 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8077 mm_player_dump_t *dump_s;
8078 dump_s = g_malloc(sizeof(mm_player_dump_t));
8080 if (dump_s == NULL) {
8081 LOGE("malloc fail");
8085 dump_s->dump_element_file = NULL;
8086 dump_s->dump_pad = NULL;
8087 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8089 if (dump_s->dump_pad) {
8090 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
8091 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]);
8092 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8093 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);
8094 /* add list for removed buffer probe and close FILE */
8095 player->dump_list = g_list_append(player->dump_list, dump_s);
8096 LOGD("%s sink pad added buffer probe for dump", factory_name);
8101 LOGE("failed to get %s sink pad added", factory_name);
8108 static GstPadProbeReturn
8109 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8111 FILE *dump_data = (FILE *) u_data;
8113 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8114 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8116 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
8118 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8120 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8122 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8124 return GST_PAD_PROBE_OK;
8128 __mmplayer_release_dump_list(GList *dump_list)
8131 GList *d_list = dump_list;
8132 for (; d_list; d_list = g_list_next(d_list)) {
8133 mm_player_dump_t *dump_s = d_list->data;
8134 if (dump_s->dump_pad) {
8135 if (dump_s->probe_handle_id)
8136 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8138 if (dump_s->dump_element_file) {
8139 fclose(dump_s->dump_element_file);
8140 dump_s->dump_element_file = NULL;
8142 MMPLAYER_FREEIF(dump_s);
8144 g_list_free(dump_list);
8150 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
8152 mm_player_t* player = (mm_player_t*) hplayer;
8156 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8157 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8159 *exist = player->has_closed_caption;
8163 return MM_ERROR_NONE;
8166 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
8170 // LOGD("unref internal gst buffer %p", buffer);
8171 gst_buffer_unref((GstBuffer *)buffer);
8177 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8179 mm_player_t *player = (mm_player_t *) hplayer;
8183 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8184 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8186 if (MMPLAYER_IS_STREAMING(player))
8187 *timeout = player->ini.live_state_change_timeout;
8189 *timeout = player->ini.localplayback_state_change_timeout;
8191 LOGD("timeout = %d", *timeout);
8194 return MM_ERROR_NONE;
8197 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8199 mm_player_t* player = (mm_player_t*) hplayer;
8203 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8204 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8206 *num = player->video_num_buffers;
8207 *extra_num = player->video_extra_num_buffers;
8209 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8212 return MM_ERROR_NONE;
8216 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
8220 MMPLAYER_RETURN_IF_FAIL(player);
8222 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8224 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8225 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8226 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8227 player->storage_info[i].id = -1;
8228 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8230 if (path_type != MMPLAYER_PATH_MAX)
8238 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8240 int ret = MM_ERROR_NONE;
8241 mm_player_t* player = (mm_player_t*)hplayer;
8242 MMMessageParamType msg_param = {0, };
8245 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8247 LOGW("state changed storage %d:%d", id, state);
8249 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8250 return MM_ERROR_NONE;
8252 /* FIXME: text path should be handled seperately. */
8253 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8254 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8255 LOGW("external storage is removed");
8257 if (player->msg_posted == FALSE) {
8258 memset(&msg_param, 0, sizeof(MMMessageParamType));
8259 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8260 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8261 player->msg_posted = TRUE;
8264 /* unrealize the player */
8265 ret = _mmplayer_unrealize(hplayer);
8266 if (ret != MM_ERROR_NONE)
8267 LOGE("failed to unrealize");
8274 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8276 int ret = MM_ERROR_NONE;
8277 mm_player_t* player = (mm_player_t*) hplayer;
8278 int idx = 0, total = 0;
8279 gchar *result = NULL, *tmp = NULL;
8282 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8283 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8285 total = *num = g_list_length(player->adaptive_info.var_list);
8287 LOGW("There is no stream variant info.");
8291 result = g_strdup("");
8292 for (idx = 0 ; idx < total ; idx++) {
8293 VariantData *v_data = NULL;
8294 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8297 gchar data[64] = {0};
8298 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8300 tmp = g_strconcat(result, data, NULL);
8304 LOGW("There is no variant data in %d", idx);
8309 *var_info = (char *)result;
8311 LOGD("variant info %d:%s", *num, *var_info);
8316 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8318 int ret = MM_ERROR_NONE;
8319 mm_player_t* player = (mm_player_t*) hplayer;
8322 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8324 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8326 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8327 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8328 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8330 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8331 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8332 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8333 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8335 /* FIXME: seek to current position for applying new variant limitation */
8343 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8345 int ret = MM_ERROR_NONE;
8346 mm_player_t* player = (mm_player_t*) hplayer;
8349 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8350 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8352 *bandwidth = player->adaptive_info.limit.bandwidth;
8353 *width = player->adaptive_info.limit.width;
8354 *height = player->adaptive_info.limit.height;
8356 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8362 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
8364 int ret = MM_ERROR_NONE;
8365 mm_player_t* player = (mm_player_t*) hplayer;
8368 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8370 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
8371 LOGW("buffer_ms will not be applied.");
8374 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
8376 if (player->streamer == NULL) {
8377 player->streamer = __mm_player_streaming_create();
8378 __mm_player_streaming_initialize(player->streamer);
8382 player->streamer->buffering_req.prebuffer_time = buffer_ms;
8384 if (rebuffer_ms >= 0)
8385 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
8392 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
8394 int ret = MM_ERROR_NONE;
8395 mm_player_t* player = (mm_player_t*) hplayer;
8398 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8399 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8401 if (player->streamer == NULL) {
8402 player->streamer = __mm_player_streaming_create();
8403 __mm_player_streaming_initialize(player->streamer);
8406 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
8407 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8409 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
8415 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8417 #define IDX_FIRST_SW_CODEC 0
8418 mm_player_t* player = (mm_player_t*) hplayer;
8419 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8420 MMHandleType attrs = 0;
8423 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8425 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8426 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8427 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8429 switch (stream_type) {
8430 case MM_PLAYER_STREAM_TYPE_AUDIO:
8431 /* to support audio codec selection, codec info have to be added in ini file as below.
8432 audio codec element hw = xxxx
8433 audio codec element sw = avdec */
8434 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8435 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8436 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8437 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8438 LOGE("There is no audio codec info for codec_type %d", codec_type);
8439 return MM_ERROR_PLAYER_NO_OP;
8442 case MM_PLAYER_STREAM_TYPE_VIDEO:
8443 /* to support video codec selection, codec info have to be added in ini file as below.
8444 video codec element hw = omx
8445 video codec element sw = avdec */
8446 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8447 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8448 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8449 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8450 LOGE("There is no video codec info for codec_type %d", codec_type);
8451 return MM_ERROR_PLAYER_NO_OP;
8455 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8456 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8460 LOGD("update %s codec_type to %d", attr_name, codec_type);
8462 attrs = MMPLAYER_GET_ATTRS(player);
8463 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8465 if (mm_attrs_commit_all(player->attrs)) {
8466 LOGE("failed to commit codec_type attributes");
8467 return MM_ERROR_PLAYER_INTERNAL;
8471 return MM_ERROR_NONE;
8475 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8477 mm_player_t* player = (mm_player_t*) hplayer;
8478 GstElement* rg_vol_element = NULL;
8482 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8484 player->sound.rg_enable = enabled;
8486 /* just hold rgvolume enable value if pipeline is not ready */
8487 if (!player->pipeline || !player->pipeline->audiobin) {
8488 LOGD("pipeline is not ready. holding rgvolume enable value\n");
8489 return MM_ERROR_NONE;
8492 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8494 if (!rg_vol_element) {
8495 LOGD("rgvolume element is not created");
8496 return MM_ERROR_PLAYER_INTERNAL;
8500 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8502 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8506 return MM_ERROR_NONE;
8510 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8512 mm_player_t* player = (mm_player_t*) hplayer;
8513 GstElement* rg_vol_element = NULL;
8514 gboolean enable = FALSE;
8518 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8519 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8521 /* just hold enable_rg value if pipeline is not ready */
8522 if (!player->pipeline || !player->pipeline->audiobin) {
8523 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
8524 *enabled = player->sound.rg_enable;
8525 return MM_ERROR_NONE;
8528 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8530 if (!rg_vol_element) {
8531 LOGD("rgvolume element is not created");
8532 return MM_ERROR_PLAYER_INTERNAL;
8535 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8540 return MM_ERROR_NONE;
8544 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8546 mm_player_t* player = (mm_player_t*) hplayer;
8547 MMHandleType attrs = 0;
8548 void *handle = NULL;
8549 int ret = MM_ERROR_NONE;
8553 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8555 attrs = MMPLAYER_GET_ATTRS(player);
8556 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8558 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8560 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8561 return MM_ERROR_PLAYER_INTERNAL;
8564 player->video_roi.scale_x = scale_x;
8565 player->video_roi.scale_y = scale_y;
8566 player->video_roi.scale_width = scale_width;
8567 player->video_roi.scale_height = scale_height;
8569 /* check video sinkbin is created */
8570 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8571 return MM_ERROR_NONE;
8573 if (!gst_video_overlay_set_video_roi_area(
8574 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8575 scale_x, scale_y, scale_width, scale_height))
8576 ret = MM_ERROR_PLAYER_INTERNAL;
8578 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8579 scale_x, scale_y, scale_width, scale_height);
8587 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8589 mm_player_t* player = (mm_player_t*) hplayer;
8590 int ret = MM_ERROR_NONE;
8594 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8595 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8597 *scale_x = player->video_roi.scale_x;
8598 *scale_y = player->video_roi.scale_y;
8599 *scale_width = player->video_roi.scale_width;
8600 *scale_height = player->video_roi.scale_height;
8602 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8603 *scale_x, *scale_y, *scale_width, *scale_height);
8609 __mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs)
8611 gboolean ret = FALSE;
8612 gint64 dur_nsec = 0;
8613 LOGD("try to update duration");
8615 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8616 player->duration = dur_nsec;
8617 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8621 if (player->duration < 0) {
8622 LOGW("duration is Non-Initialized !!!");
8623 player->duration = 0;
8626 /* update streaming service type */
8627 player->streaming_type = __mmplayer_get_stream_service_type(player);
8629 /* check duration is OK */
8630 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
8631 /* FIXIT : find another way to get duration here. */
8632 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8639 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8641 /* update audio params
8642 NOTE : We need original audio params and it can be only obtained from src pad of audio
8643 decoder. Below code only valid when we are not using 'resampler' just before
8644 'audioconverter'. */
8645 GstCaps *caps_a = NULL;
8647 gint samplerate = 0, channels = 0;
8648 GstStructure* p = NULL;
8650 LOGD("try to update audio attrs");
8652 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8653 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8655 pad = gst_element_get_static_pad(
8656 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8659 LOGW("failed to get pad from audiosink");
8663 caps_a = gst_pad_get_current_caps(pad);
8666 LOGW("not ready to get audio caps");
8667 gst_object_unref(pad);
8671 p = gst_caps_get_structure(caps_a, 0);
8673 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8675 gst_structure_get_int(p, "rate", &samplerate);
8676 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8678 gst_structure_get_int(p, "channels", &channels);
8679 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8681 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8683 gst_caps_unref(caps_a);
8684 gst_object_unref(pad);
8690 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8692 LOGD("try to update video attrs");
8694 GstCaps *caps_v = NULL;
8698 GstStructure* p = NULL;
8700 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8701 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8703 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8705 LOGD("no videosink sink pad");
8709 caps_v = gst_pad_get_current_caps(pad);
8710 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8711 if (!caps_v && player->v_stream_caps) {
8712 caps_v = player->v_stream_caps;
8713 gst_caps_ref(caps_v);
8717 LOGD("no negitiated caps from videosink");
8718 gst_object_unref(pad);
8722 p = gst_caps_get_structure(caps_v, 0);
8723 gst_structure_get_int(p, "width", &width);
8724 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8726 gst_structure_get_int(p, "height", &height);
8727 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8729 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8731 SECURE_LOGD("width : %d height : %d", width, height);
8733 gst_caps_unref(caps_v);
8734 gst_object_unref(pad);
8737 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8738 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8745 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8747 gboolean ret = FALSE;
8748 guint64 data_size = 0;
8752 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8753 if (!player->duration)
8756 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8757 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8758 if (stat(path, &sb) == 0)
8759 data_size = (guint64)sb.st_size;
8761 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8762 data_size = player->http_content_size;
8765 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8768 guint64 bitrate = 0;
8769 guint64 msec_dur = 0;
8771 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8773 bitrate = data_size * 8 * 1000 / msec_dur;
8774 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8775 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8779 LOGD("player duration is less than 0");
8783 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8784 if (player->total_bitrate) {
8785 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
8793 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile* data, const char *uri, int uri_type)
8795 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8796 data->uri_type = uri_type;
8799 __mmplayer_set_mem_uri(MMPlayerParseProfile* data, char *path, void *param)
8801 int ret = MM_ERROR_PLAYER_INVALID_URI;
8803 char *buffer = NULL;
8804 char *seperator = strchr(path, ',');
8805 char ext[100] = {0,}, size[100] = {0,};
8808 if ((buffer = strstr(path, "ext="))) {
8809 buffer += strlen("ext=");
8811 if (strlen(buffer)) {
8812 strncpy(ext, buffer, 99);
8814 if ((seperator = strchr(ext, ','))
8815 || (seperator = strchr(ext, ' '))
8816 || (seperator = strchr(ext, '\0'))) {
8817 seperator[0] = '\0';
8822 if ((buffer = strstr(path, "size="))) {
8823 buffer += strlen("size=");
8825 if (strlen(buffer) > 0) {
8826 strncpy(size, buffer, 99);
8828 if ((seperator = strchr(size, ','))
8829 || (seperator = strchr(size, ' '))
8830 || (seperator = strchr(size, '\0'))) {
8831 seperator[0] = '\0';
8834 mem_size = atoi(size);
8839 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8841 if (mem_size && param) {
8842 if (data->input_mem.buf)
8843 free(data->input_mem.buf);
8844 data->input_mem.buf = malloc(mem_size);
8846 if (data->input_mem.buf) {
8847 memcpy(data->input_mem.buf, param, mem_size);
8848 data->input_mem.len = mem_size;
8849 ret = MM_ERROR_NONE;
8851 LOGE("failed to alloc mem %d", mem_size);
8852 ret = MM_ERROR_PLAYER_INTERNAL;
8855 data->input_mem.offset = 0;
8856 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8863 __mmplayer_set_file_uri(MMPlayerParseProfile* data, const char *uri)
8865 gchar *location = NULL;
8868 int ret = MM_ERROR_NONE;
8870 if ((path = strstr(uri, "file://"))) {
8871 location = g_filename_from_uri(uri, NULL, &err);
8872 if (!location || (err != NULL)) {
8873 LOGE("Invalid URI '%s' for filesrc: %s", path,
8874 (err != NULL) ? err->message : "unknown error");
8880 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8881 return MM_ERROR_PLAYER_INVALID_URI;
8883 LOGD("path from uri: %s", location);
8886 path = (location != NULL) ? (location) : ((char *)uri);
8889 ret = util_exist_file_path(path);
8891 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8892 if (ret == MM_ERROR_NONE) {
8893 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8894 if (util_is_sdp_file(path)) {
8895 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8896 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8898 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8900 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8901 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8903 LOGE("invalid uri, could not play..\n");
8904 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8913 static MMPlayerVideoStreamDataType*
8914 __mmplayer_create_stream_from_pad(GstPad *pad)
8916 GstCaps *caps = NULL;
8917 GstStructure *structure = NULL;
8918 unsigned int fourcc = 0;
8919 const gchar *string_format = NULL;
8920 MMPlayerVideoStreamDataType *stream = NULL;
8922 MMPixelFormatType format;
8924 caps = gst_pad_get_current_caps(pad);
8926 LOGE("Caps is NULL.");
8930 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
8931 structure = gst_caps_get_structure(caps, 0);
8932 gst_structure_get_int(structure, "width", &width);
8933 gst_structure_get_int(structure, "height", &height);
8934 string_format = gst_structure_get_string(structure, "format");
8936 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
8937 format = util_get_pixtype(fourcc);
8938 gst_caps_unref(caps);
8941 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
8942 LOGE("Wrong condition!!");
8946 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
8948 LOGE("failed to alloc mem for video data");
8952 stream->width = width;
8953 stream->height = height;
8954 stream->format = format;
8960 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
8962 unsigned int pitch = 0;
8964 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
8966 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
8967 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
8968 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
8969 stream->stride[index] = pitch;
8970 stream->elevation[index] = stream->height;
8975 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
8977 if (stream->format == MM_PIXEL_FORMAT_I420) {
8978 int ret = TBM_SURFACE_ERROR_NONE;
8979 tbm_surface_h surface;
8980 tbm_surface_info_s info;
8982 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
8984 ret = tbm_surface_get_info(surface, &info);
8985 if (ret != TBM_SURFACE_ERROR_NONE) {
8986 tbm_surface_destroy(surface);
8990 tbm_surface_destroy(surface);
8991 stream->stride[0] = info.planes[0].stride;
8992 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
8993 stream->stride[1] = info.planes[1].stride;
8994 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
8995 stream->stride[2] = info.planes[2].stride;
8996 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
8997 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
8998 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
8999 stream->stride[0] = stream->width * 4;
9000 stream->elevation[0] = stream->height;
9001 stream->bo_size = stream->stride[0] * stream->height;
9003 LOGE("Not support format %d", stream->format);
9011 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9013 tbm_bo_handle thandle;
9015 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9016 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9017 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9021 unsigned char *src = NULL;
9022 unsigned char *dest = NULL;
9023 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9025 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9027 LOGE("fail to gst_memory_map");
9031 if (!mapinfo.data) {
9032 LOGE("data pointer is wrong");
9036 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9037 if (!stream->bo[0]) {
9038 LOGE("Fail to tbm_bo_alloc!!");
9042 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9044 LOGE("thandle pointer is wrong");
9048 if (stream->format == MM_PIXEL_FORMAT_I420) {
9049 src_stride[0] = GST_ROUND_UP_4(stream->width);
9050 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9051 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9052 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9055 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9056 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9058 for (i = 0; i < 3; i++) {
9059 src = mapinfo.data + src_offset[i];
9060 dest = thandle.ptr + dest_offset[i];
9065 for (j = 0; j < stream->height >> k; j++) {
9066 memcpy(dest, src, stream->width>>k);
9067 src += src_stride[i];
9068 dest += stream->stride[i];
9071 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9072 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9074 LOGE("Not support format %d", stream->format);
9078 tbm_bo_unmap(stream->bo[0]);
9079 gst_memory_unmap(mem, &mapinfo);
9085 tbm_bo_unmap(stream->bo[0]);
9088 gst_memory_unmap(mem, &mapinfo);
9094 __mmplayer_set_pause_state(mm_player_t *player)
9096 if (player->sent_bos)
9099 /* rtsp case, get content attrs by GstMessage */
9100 if (MMPLAYER_IS_RTSP_STREAMING(player))
9103 /* it's first time to update all content attrs. */
9104 __mmplayer_update_content_attrs(player, ATTR_ALL);
9108 __mmplayer_set_playing_state(mm_player_t *player)
9110 gchar *audio_codec = NULL;
9112 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9113 /* initialize because auto resume is done well. */
9114 player->resumed_by_rewind = FALSE;
9115 player->playback_rate = 1.0;
9118 if (player->sent_bos)
9121 /* try to get content metadata */
9123 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9124 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9125 * legacy mmfw-player api
9127 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9129 if ((player->cmd == MMPLAYER_COMMAND_START)
9130 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9131 __mmplayer_handle_missed_plugin(player);
9134 /* check audio codec field is set or not
9135 * we can get it from typefinder or codec's caps.
9137 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9139 /* The codec format can't be sent for audio only case like amr, mid etc.
9140 * Because, parser don't make related TAG.
9141 * So, if it's not set yet, fill it with found data.
9144 if (g_strrstr(player->type, "audio/midi"))
9145 audio_codec = "MIDI";
9146 else if (g_strrstr(player->type, "audio/x-amr"))
9147 audio_codec = "AMR";
9148 else if (g_strrstr(player->type, "audio/mpeg")
9149 && !g_strrstr(player->type, "mpegversion= (int)1"))
9150 audio_codec = "AAC";
9152 audio_codec = "unknown";
9154 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9156 if (mm_attrs_commit_all(player->attrs))
9157 LOGE("failed to update attributes\n");
9159 LOGD("set audio codec type with caps\n");