4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
42 #include "mm_player_priv.h"
43 #include "mm_player_ini.h"
44 #include "mm_player_attrs.h"
45 #include "mm_player_capture.h"
46 #include "mm_player_utils.h"
47 #include "mm_player_tracks.h"
48 #include "mm_player_360.h"
49 #include "mm_player_gst.h"
51 #include <system_info.h>
52 #include <sound_manager.h>
53 #include <gst/allocators/gsttizenmemory.h>
54 #include <tbm_surface_internal.h>
56 /*===========================================================================================
58 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
60 ========================================================================================== */
62 /*---------------------------------------------------------------------------
63 | GLOBAL CONSTANT DEFINITIONS: |
64 ---------------------------------------------------------------------------*/
66 /*---------------------------------------------------------------------------
67 | IMPORTED VARIABLE DECLARATIONS: |
68 ---------------------------------------------------------------------------*/
70 /*---------------------------------------------------------------------------
71 | IMPORTED FUNCTION DECLARATIONS: |
72 ---------------------------------------------------------------------------*/
74 /*---------------------------------------------------------------------------
76 ---------------------------------------------------------------------------*/
77 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
78 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
80 #define MM_VOLUME_FACTOR_DEFAULT 1.0
81 #define MM_VOLUME_FACTOR_MIN 0
82 #define MM_VOLUME_FACTOR_MAX 1.0
84 /* Don't need to sleep for sound fadeout
85 * fadeout related fucntion will be deleted(Deprecated)
87 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
89 #define DEFAULT_PLAYBACK_RATE 1.0
90 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
92 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
93 (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
94 (player->ini.http_use_file_buffer) && \
95 (player->http_file_buffering_path) && \
96 (strlen(player->http_file_buffering_path) > 0))
98 #define PLAYER_DISPLAY_MODE_DST_ROI 5
100 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
102 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
103 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
104 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
105 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
107 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
108 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
110 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
112 /*---------------------------------------------------------------------------
113 | LOCAL CONSTANT DEFINITIONS: |
114 ---------------------------------------------------------------------------*/
116 /*---------------------------------------------------------------------------
117 | LOCAL DATA TYPE DEFINITIONS: |
118 ---------------------------------------------------------------------------*/
120 /*---------------------------------------------------------------------------
121 | GLOBAL VARIABLE DEFINITIONS: |
122 ---------------------------------------------------------------------------*/
124 /*---------------------------------------------------------------------------
125 | LOCAL VARIABLE DEFINITIONS: |
126 ---------------------------------------------------------------------------*/
127 static sound_stream_info_h stream_info;
129 /*---------------------------------------------------------------------------
130 | LOCAL FUNCTION PROTOTYPES: |
131 ---------------------------------------------------------------------------*/
132 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
133 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
134 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
135 static int __mmplayer_gst_create_video_sink_bin(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
136 static int __mmplayer_gst_create_audio_sink_bin(mm_player_t* player);
137 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
139 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
140 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
141 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
142 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
143 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
144 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
145 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
146 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
147 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
148 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
149 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
151 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
152 static void __mmplayer_release_misc(mm_player_t* player);
153 static void __mmplayer_release_misc_post(mm_player_t* player);
154 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
155 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
156 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
158 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
160 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
161 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
162 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
163 static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
164 static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
165 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
166 static gpointer __mmplayer_gapless_play_thread(gpointer data);
167 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
168 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
169 static void __mmplayer_release_dump_list(GList *dump_list);
170 static int __mmplayer_gst_realize(mm_player_t* player);
171 static int __mmplayer_gst_unrealize(mm_player_t* player);
172 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
173 static int __mmplayer_gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
176 static gboolean __mmplayer_verify_gapless_play_path(mm_player_t *player);
177 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
178 static void __mmplayer_check_pipeline(mm_player_t* player);
179 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
180 static void __mmplayer_deactivate_old_path(mm_player_t *player);
181 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
182 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
183 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
184 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
185 static void __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
186 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
187 static gboolean __mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs);
188 static gboolean __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs);
189 static gboolean __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs);
190 static gboolean __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs);
192 static void __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile* data, const char *uri, int uri_type);
193 static int __mmplayer_set_mem_uri(MMPlayerParseProfile* data, char *path, void *param);
194 static int __mmplayer_set_file_uri(MMPlayerParseProfile* data, const char *uri);
196 static MMPlayerVideoStreamDataType* __mmplayer_create_stream_from_pad(GstPad *pad);
197 static void __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem);
198 static gboolean __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream);
199 static gboolean __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem);
201 static void __mmplayer_set_pause_state(mm_player_t *player);
202 static void __mmplayer_set_playing_state(mm_player_t *player);
203 /*===========================================================================================
205 | FUNCTION DEFINITIONS |
207 ========================================================================================== */
211 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
215 count = gst_tag_list_get_tag_size(list, tag);
217 LOGD("count = %d", count);
219 for (i = 0; i < count; i++) {
222 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
223 if (!gst_tag_list_get_string_index(list, tag, i, &str))
224 g_assert_not_reached();
226 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
229 g_print(" %15s: %s\n", gst_tag_get_nick(tag), str);
231 g_print(" : %s\n", str);
238 /* This function should be called after the pipeline goes PAUSED or higher
241 __mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
243 static gboolean has_duration = FALSE;
244 static gboolean has_video_attrs = FALSE;
245 static gboolean has_audio_attrs = FALSE;
246 static gboolean has_bitrate = FALSE;
247 gboolean missing_only = FALSE;
248 gboolean all = FALSE;
249 MMHandleType attrs = 0;
253 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
255 /* check player state here */
256 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
257 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
258 /* give warning now only */
259 LOGW("be careful. content attributes may not available in this state ");
262 /* get content attribute first */
263 attrs = MMPLAYER_GET_ATTRS(player);
265 LOGE("cannot get content attribute");
269 /* get update flag */
271 if (flag & ATTR_MISSING_ONLY) {
273 LOGD("updating missed attr only");
276 if (flag & ATTR_ALL) {
278 has_duration = FALSE;
279 has_video_attrs = FALSE;
280 has_audio_attrs = FALSE;
283 LOGD("updating all attrs");
286 if (missing_only && all) {
287 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
288 missing_only = FALSE;
291 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
292 has_duration = __mmplayer_update_duration_attrs(player, attrs);
294 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
295 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
297 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
298 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
300 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
301 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
304 if (mm_attrs_commit_all(attrs)) {
305 LOGE("failed to update attributes\n");
314 MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
316 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
320 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
322 player->pipeline->mainbin &&
323 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
324 STREAMING_SERVICE_NONE);
326 /* streaming service type if streaming */
327 if (!MMPLAYER_IS_STREAMING(player))
328 return STREAMING_SERVICE_NONE;
330 streaming_type = (player->duration == 0) ?
331 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
333 switch (streaming_type) {
334 case STREAMING_SERVICE_LIVE:
335 LOGD("it's live streaming");
337 case STREAMING_SERVICE_VOD:
338 LOGD("it's vod streaming");
341 LOGE("should not get here");
347 return streaming_type;
351 /* this function sets the player state and also report
352 * it to applicaton by calling callback function
355 __mmplayer_set_state(mm_player_t *player, int state)
357 MMMessageParamType msg = {0, };
359 MMPLAYER_RETURN_IF_FAIL(player);
361 if (MMPLAYER_CURRENT_STATE(player) == state) {
362 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
363 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
367 /* update player states */
368 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
369 MMPLAYER_CURRENT_STATE(player) = state;
371 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
372 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
375 MMPLAYER_PRINT_STATE(player);
377 switch (MMPLAYER_CURRENT_STATE(player)) {
378 case MM_PLAYER_STATE_NULL:
379 case MM_PLAYER_STATE_READY:
381 case MM_PLAYER_STATE_PAUSED:
382 __mmplayer_set_pause_state(player);
384 case MM_PLAYER_STATE_PLAYING:
385 __mmplayer_set_playing_state(player);
387 case MM_PLAYER_STATE_NONE:
389 LOGW("invalid target state, there is nothing to do.\n");
394 /* post message to application */
395 if (MMPLAYER_TARGET_STATE(player) == state) {
396 /* fill the message with state of player */
397 msg.union_type = MM_MSG_UNION_STATE;
398 msg.state.previous = MMPLAYER_PREV_STATE(player);
399 msg.state.current = MMPLAYER_CURRENT_STATE(player);
401 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
403 /* state changed by resource callback */
404 if (player->interrupted_by_resource) {
405 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
406 } else { /* state changed by usecase */
407 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
410 LOGD("intermediate state, do nothing.\n");
411 MMPLAYER_PRINT_STATE(player);
415 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
416 && !player->sent_bos) {
417 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
418 player->sent_bos = TRUE;
425 __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command)
427 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
428 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
430 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
432 //LOGD("incomming command : %d \n", command);
434 current_state = MMPLAYER_CURRENT_STATE(player);
435 pending_state = MMPLAYER_PENDING_STATE(player);
437 MMPLAYER_PRINT_STATE(player);
440 case MMPLAYER_COMMAND_CREATE:
442 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
444 if (current_state == MM_PLAYER_STATE_NULL ||
445 current_state == MM_PLAYER_STATE_READY ||
446 current_state == MM_PLAYER_STATE_PAUSED ||
447 current_state == MM_PLAYER_STATE_PLAYING)
452 case MMPLAYER_COMMAND_DESTROY:
454 /* destroy can called anytime */
456 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
460 case MMPLAYER_COMMAND_REALIZE:
462 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
464 if (pending_state != MM_PLAYER_STATE_NONE) {
467 /* need ready state to realize */
468 if (current_state == MM_PLAYER_STATE_READY)
471 if (current_state != MM_PLAYER_STATE_NULL)
477 case MMPLAYER_COMMAND_UNREALIZE:
479 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
481 if (current_state == MM_PLAYER_STATE_NULL)
486 case MMPLAYER_COMMAND_START:
488 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
490 if (pending_state == MM_PLAYER_STATE_NONE) {
491 if (current_state == MM_PLAYER_STATE_PLAYING)
493 else if (current_state != MM_PLAYER_STATE_READY &&
494 current_state != MM_PLAYER_STATE_PAUSED)
496 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
498 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
499 LOGD("player is going to paused state, just change the pending state as playing");
505 case MMPLAYER_COMMAND_STOP:
507 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
509 if (current_state == MM_PLAYER_STATE_READY)
512 /* need playing/paused state to stop */
513 if (current_state != MM_PLAYER_STATE_PLAYING &&
514 current_state != MM_PLAYER_STATE_PAUSED)
519 case MMPLAYER_COMMAND_PAUSE:
521 if (MMPLAYER_IS_LIVE_STREAMING(player))
524 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
525 goto NOT_COMPLETED_SEEK;
527 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
529 if (pending_state == MM_PLAYER_STATE_NONE) {
530 if (current_state == MM_PLAYER_STATE_PAUSED)
532 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
534 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
536 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
537 if (current_state == MM_PLAYER_STATE_PAUSED)
538 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
545 case MMPLAYER_COMMAND_RESUME:
547 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
548 goto NOT_COMPLETED_SEEK;
550 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
552 if (pending_state == MM_PLAYER_STATE_NONE) {
553 if (current_state == MM_PLAYER_STATE_PLAYING)
555 else if (current_state != MM_PLAYER_STATE_PAUSED)
557 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
559 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
560 LOGD("player is going to paused state, just change the pending state as playing");
569 player->cmd = command;
571 return MM_ERROR_NONE;
574 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
575 MMPLAYER_STATE_GET_NAME(current_state), command);
576 return MM_ERROR_PLAYER_INVALID_STATE;
579 LOGW("not completed seek");
580 return MM_ERROR_PLAYER_DOING_SEEK;
583 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
584 return MM_ERROR_PLAYER_NO_OP;
587 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
588 return MM_ERROR_PLAYER_NO_OP;
591 static gpointer __mmplayer_gapless_play_thread(gpointer data)
593 mm_player_t* player = (mm_player_t*) data;
594 MMPlayerGstElement *mainbin = NULL;
596 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
598 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
599 while (!player->gapless_play_thread_exit) {
600 LOGD("gapless play thread started. waiting for signal.\n");
601 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
603 LOGD("reconfigure pipeline for gapless play.\n");
605 if (player->gapless_play_thread_exit) {
606 if (player->gapless.reconfigure) {
607 player->gapless.reconfigure = false;
608 MMPLAYER_PLAYBACK_UNLOCK(player);
610 LOGD("exiting gapless play thread\n");
614 mainbin = player->pipeline->mainbin;
616 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
617 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
618 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
619 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
620 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
622 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
624 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
630 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
632 GSource *source = NULL;
636 source = g_main_context_find_source_by_id(context, source_id);
638 if (source != NULL) {
639 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
640 g_source_destroy(source);
646 void __mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
648 mm_player_t* player = (mm_player_t*)hplayer;
649 GstMessage *msg = NULL;
650 GQueue *queue = NULL;
653 MMPLAYER_RETURN_IF_FAIL(player);
655 /* disconnecting bus watch */
656 if (player->bus_watcher)
657 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
658 player->bus_watcher = 0;
660 /* destroy the gst bus msg thread */
661 if (player->bus_msg_thread) {
662 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
663 player->bus_msg_thread_exit = TRUE;
664 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
665 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
667 LOGD("gst bus msg thread exit.");
668 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
669 player->bus_msg_thread = NULL;
671 g_mutex_clear(&player->bus_msg_thread_mutex);
672 g_cond_clear(&player->bus_msg_thread_cond);
675 g_mutex_lock(&player->bus_msg_q_lock);
676 queue = player->bus_msg_q;
677 while (!g_queue_is_empty(queue)) {
678 msg = (GstMessage *)g_queue_pop_head(queue);
683 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
684 gst_message_unref(msg);
686 g_mutex_unlock(&player->bus_msg_q_lock);
692 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
694 GstElement* parent = NULL;
696 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
698 /* if we have no fakesink. this meas we are using decodebin which doesn'
699 t need to add extra fakesink */
700 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
703 MMPLAYER_FSINK_LOCK(player);
708 /* get parent of fakesink */
709 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
711 LOGD("fakesink already removed\n");
715 gst_element_set_locked_state(fakesink->gst, TRUE);
717 /* setting the state to NULL never returns async
718 * so no need to wait for completion of state transiton
720 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
721 LOGE("fakesink state change failure!\n");
722 /* FIXIT : should I return here? or try to proceed to next? */
725 /* remove fakesink from it's parent */
726 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
727 LOGE("failed to remove fakesink\n");
729 gst_object_unref(parent);
734 gst_object_unref(parent);
736 LOGD("state-holder removed\n");
738 gst_element_set_locked_state(fakesink->gst, FALSE);
740 MMPLAYER_FSINK_UNLOCK(player);
745 gst_element_set_locked_state(fakesink->gst, FALSE);
747 MMPLAYER_FSINK_UNLOCK(player);
751 static GstPadProbeReturn
752 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
754 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
755 return GST_PAD_PROBE_OK;
759 __mmplayer_gst_selector_update_start_time(mm_player_t* player, MMPlayerTrackType stream_type)
761 gint64 stop_running_time = 0;
762 gint64 position_running_time = 0;
766 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
767 if ((player->gapless.update_segment[idx] == TRUE) ||
768 !(player->selector[idx].event_probe_id)) {
769 /* LOGW("[%d] skip", idx); */
773 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
775 gst_segment_to_running_time(&player->gapless.segment[idx],
776 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
777 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
779 gst_segment_to_running_time(&player->gapless.segment[idx],
780 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
782 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
784 gst_segment_to_running_time(&player->gapless.segment[idx],
785 GST_FORMAT_TIME, player->duration);
788 position_running_time =
789 gst_segment_to_running_time(&player->gapless.segment[idx],
790 GST_FORMAT_TIME, player->gapless.segment[idx].position);
792 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
793 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
795 GST_TIME_ARGS(stop_running_time),
796 GST_TIME_ARGS(position_running_time),
797 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
798 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
800 position_running_time = MAX(position_running_time, stop_running_time);
801 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
802 GST_FORMAT_TIME, player->gapless.segment[idx].start);
803 position_running_time = MAX(0, position_running_time);
804 position = MAX(position, position_running_time);
808 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
809 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
810 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
812 player->gapless.start_time[stream_type] += position;
818 static GstPadProbeReturn
819 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
821 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
822 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
823 mm_player_t *player = (mm_player_t*)data;
824 GstCaps *caps = NULL;
825 GstStructure *str = NULL;
826 const gchar *name = NULL;
827 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
828 gboolean caps_ret = TRUE;
830 if (GST_EVENT_IS_DOWNSTREAM(event) &&
831 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
832 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
833 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
834 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
836 } else if (GST_EVENT_IS_UPSTREAM(event) &&
837 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
841 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
845 if (strstr(name, "audio")) {
846 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
847 } else if (strstr(name, "video")) {
848 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
850 /* text track is not supportable */
851 LOGE("invalid name %s", name);
855 switch (GST_EVENT_TYPE(event)) {
858 /* in case of gapless, drop eos event not to send it to sink */
859 if (player->gapless.reconfigure && !player->msg_posted) {
860 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
861 ret = GST_PAD_PROBE_DROP;
865 case GST_EVENT_STREAM_START:
867 __mmplayer_gst_selector_update_start_time(player, stream_type);
870 case GST_EVENT_FLUSH_STOP:
872 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
873 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
874 player->gapless.start_time[stream_type] = 0;
877 case GST_EVENT_SEGMENT:
882 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
883 gst_event_copy_segment(event, &segment);
885 if (segment.format != GST_FORMAT_TIME)
888 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
889 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
890 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
891 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
892 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
893 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
895 /* keep the all the segment ev to cover the seeking */
896 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
897 player->gapless.update_segment[stream_type] = TRUE;
899 if (!player->gapless.running)
902 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
904 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
906 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
907 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
908 gst_event_unref(event);
909 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
915 gdouble proportion = 0.0;
916 GstClockTimeDiff diff = 0;
917 GstClockTime timestamp = 0;
918 gint64 running_time_diff = -1;
920 GstEvent *tmpev = NULL;
922 running_time_diff = player->gapless.segment[stream_type].base;
924 if (running_time_diff <= 0) /* don't need to adjust */
927 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
928 gst_event_unref(event);
930 if (timestamp < running_time_diff) {
931 LOGW("QOS event from previous group");
932 ret = GST_PAD_PROBE_DROP;
936 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
937 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
938 stream_type, GST_TIME_ARGS(timestamp),
939 GST_TIME_ARGS(running_time_diff),
940 GST_TIME_ARGS(timestamp - running_time_diff));
942 timestamp -= running_time_diff;
944 /* That case is invalid for QoS events */
945 if (diff < 0 && -diff > timestamp) {
946 LOGW("QOS event from previous group");
947 ret = GST_PAD_PROBE_DROP;
951 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
952 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
962 gst_caps_unref(caps);
966 /* create fakesink for audio or video path witout audiobin or videobin */
968 __mmplayer_gst_make_fakesink(mm_player_t *player, GstPad *pad, const gchar *name)
970 GstElement *pipeline = NULL;
971 GstElement *fakesink = NULL;
972 GstPad *sinkpad = NULL;
975 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
977 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
980 fakesink = gst_element_factory_make("fakesink", NULL);
981 if (fakesink == NULL) {
982 LOGE("failed to create fakesink");
986 /* store it as it's sink element */
987 __mmplayer_add_sink(player, fakesink);
989 gst_bin_add(GST_BIN(pipeline), fakesink);
992 sinkpad = gst_element_get_static_pad(fakesink, "sink");
994 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
996 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
997 LOGE("failed to link fakesink");
998 gst_object_unref(GST_OBJECT(fakesink));
1002 if (strstr(name, "video")) {
1003 if (player->v_stream_caps) {
1004 gst_caps_unref(player->v_stream_caps);
1005 player->v_stream_caps = NULL;
1007 if (player->ini.set_dump_element_flag)
1008 __mmplayer_add_dump_buffer_probe(player, fakesink);
1011 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1012 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1016 gst_object_unref(GST_OBJECT(sinkpad));
1023 __mmplayer_gst_make_selector(mm_player_t *player, enum MainElementID elem_idx, MMPlayerTrackType stream_type)
1025 GstElement *pipeline = NULL;
1026 GstElement *selector = NULL;
1027 GstPad *srcpad = NULL;
1030 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1032 selector = gst_element_factory_make("input-selector", NULL);
1034 LOGE("failed to create input-selector");
1037 g_object_set(selector, "sync-streams", TRUE, NULL);
1039 player->pipeline->mainbin[elem_idx].id = elem_idx;
1040 player->pipeline->mainbin[elem_idx].gst = selector;
1042 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1044 srcpad = gst_element_get_static_pad(selector, "src");
1046 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1047 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1048 __mmplayer_gst_selector_blocked, NULL, NULL);
1049 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1050 __mmplayer_gst_selector_event_probe, player, NULL);
1052 gst_element_set_state(selector, GST_STATE_PAUSED);
1054 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1055 gst_bin_add(GST_BIN(pipeline), selector);
1062 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1064 mm_player_t *player = NULL;
1065 GstElement *selector = NULL;
1066 GstCaps *caps = NULL;
1067 GstStructure *str = NULL;
1068 const gchar *name = NULL;
1069 GstPad *sinkpad = NULL;
1070 gboolean first_track = FALSE;
1071 gboolean caps_ret = TRUE;
1073 enum MainElementID elem_idx = MMPLAYER_M_NUM;
1074 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1077 player = (mm_player_t*)data;
1080 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1081 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1083 LOGD("pad-added signal handling");
1085 /* get mimetype from caps */
1086 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1090 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1091 /* LOGD("detected mimetype : %s", name); */
1093 if (strstr(name, "video")) {
1095 gchar *caps_str = NULL;
1097 caps_str = gst_caps_to_string(caps);
1098 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1099 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1100 player->set_mode.video_zc = TRUE;
1102 MMPLAYER_FREEIF(caps_str);
1104 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1105 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1107 LOGD("surface type : %d", stype);
1109 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1110 __mmplayer_gst_create_sinkbin(elem, pad, player);
1114 /* in case of exporting video frame, it requires the 360 video filter.
1115 * it will be handled in _no_more_pads(). */
1116 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)){
1117 __mmplayer_gst_make_fakesink(player, pad, name);
1121 LOGD("video selector is required");
1122 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1123 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1124 } else if (strstr(name, "audio")) {
1125 gint samplerate = 0;
1128 gst_structure_get_int(str, "rate", &samplerate);
1129 gst_structure_get_int(str, "channels", &channels);
1131 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1132 __mmplayer_gst_create_sinkbin(elem, pad, player);
1136 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1137 __mmplayer_gst_make_fakesink(player, pad, name);
1141 LOGD("audio selector is required");
1142 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1143 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1145 } else if (strstr(name, "text")) {
1146 LOGD("text selector is required");
1147 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1148 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1150 LOGE("invalid caps info");
1154 /* check selector and create it */
1155 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1156 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1161 LOGD("input-selector is already created.");
1165 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1167 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1169 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1170 LOGE("failed to link selector");
1171 gst_object_unref(GST_OBJECT(selector));
1176 LOGD("this track will be activated");
1177 g_object_set(selector, "active-pad", sinkpad, NULL);
1180 __mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1186 gst_caps_unref(caps);
1189 gst_object_unref(GST_OBJECT(sinkpad));
1196 static gboolean __mmplayer_create_sink_path(mm_player_t* player, GstElement* selector, MMPlayerTrackType type)
1198 GstPad* srcpad = NULL;
1201 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1203 LOGD("type %d", type);
1206 LOGD("there is no %d track", type);
1210 srcpad = gst_element_get_static_pad(selector, "src");
1212 LOGE("failed to get srcpad from selector");
1216 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1218 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1220 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1221 if (player->selector[type].block_id) {
1222 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1223 player->selector[type].block_id = 0;
1227 gst_object_unref(GST_OBJECT(srcpad));
1235 static void __mmplayer_set_decode_track_info(mm_player_t* player, MMPlayerTrackType type)
1237 MMHandleType attrs = 0;
1238 gint active_index = 0;
1241 MMPLAYER_RETURN_IF_FAIL(player);
1243 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1245 /* change track to active pad */
1246 active_index = player->selector[type].active_pad_index;
1247 if ((active_index != DEFAULT_TRACK) &&
1248 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1249 LOGW("failed to change %d type track to %d", type, active_index);
1250 player->selector[type].active_pad_index = DEFAULT_TRACK;
1254 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1255 attrs = MMPLAYER_GET_ATTRS(player);
1257 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1258 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1260 if (mm_attrs_commit_all(attrs))
1261 LOGW("failed to commit attrs.");
1263 LOGW("cannot get content attribute");
1271 static gboolean __mmplayer_create_audio_sink_path(mm_player_t* player, GstElement* audio_selector)
1274 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1276 if (!audio_selector) {
1277 LOGD("there is no audio track");
1279 /* in case the source is changed, output can be changed. */
1280 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1281 LOGD("remove previous audiobin if it exist");
1283 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1284 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1286 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1287 MMPLAYER_FREEIF(player->pipeline->audiobin);
1290 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1291 __mmplayer_pipeline_complete(NULL, player);
1296 /* apply the audio track information */
1297 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1299 /* create audio sink path */
1300 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1301 LOGE("failed to create audio sink path");
1309 static gboolean __mmplayer_create_text_sink_path(mm_player_t* player, GstElement* text_selector)
1312 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1314 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1315 LOGD("text path is not supproted");
1319 /* apply the text track information */
1320 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1322 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1323 player->has_closed_caption = TRUE;
1325 /* create text decode path */
1326 player->no_more_pad = TRUE;
1328 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1329 LOGE("failed to create text sink path");
1338 __mmplayer_gst_set_queue2_buffering(mm_player_t *player)
1340 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
1342 gint init_buffering_time = 0;
1343 guint buffer_bytes = 0;
1344 gint64 dur_bytes = 0L;
1347 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1348 player->pipeline->mainbin && player->streamer, FALSE);
1350 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
1351 buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
1353 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
1354 LOGD("pre buffer time: %d ms, buffer size : %d", init_buffering_time, buffer_bytes);
1356 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
1358 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1359 LOGE("fail to get duration.");
1361 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1362 * use file information was already set on Q2 when it was created. */
1363 __mm_player_streaming_set_queue2(player->streamer,
1364 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1365 TRUE, /* use_buffering */
1367 init_buffering_time,
1368 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1370 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1377 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1379 mm_player_t *player = NULL;
1380 GstElement *video_selector = NULL;
1381 GstElement *audio_selector = NULL;
1382 GstElement *text_selector = NULL;
1385 player = (mm_player_t*) data;
1387 LOGD("no-more-pad signal handling");
1389 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1390 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1391 LOGW("player is shutting down");
1395 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1396 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1397 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1398 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1399 LOGE("failed to set queue2 buffering");
1404 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1405 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1406 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1408 /* create video path followed by video-select */
1409 if (video_selector && !audio_selector && !text_selector)
1410 player->no_more_pad = TRUE;
1412 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1415 /* create audio path followed by audio-select */
1416 if (audio_selector && !text_selector)
1417 player->no_more_pad = TRUE;
1419 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1422 /* create text path followed by text-select */
1423 __mmplayer_create_text_sink_path(player, text_selector);
1426 if (player->gapless.reconfigure) {
1427 player->gapless.reconfigure = FALSE;
1428 MMPLAYER_PLAYBACK_UNLOCK(player);
1435 __mmplayer_gst_add_sinkbin_to_pipeline(mm_player_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1437 gboolean ret = FALSE;
1438 GstElement *pipeline = NULL;
1439 GstPad *sinkpad = NULL;
1442 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1443 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1445 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1447 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1449 LOGE("failed to get pad from sinkbin");
1455 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1456 LOGE("failed to link sinkbin for reusing");
1457 goto EXIT; /* exit either pass or fail */
1461 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1462 LOGE("failed to set state(READY) to sinkbin");
1467 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1468 LOGE("failed to add sinkbin to pipeline");
1473 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1474 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1479 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1480 LOGE("failed to set state(PAUSED) to sinkbin");
1489 gst_object_unref(GST_OBJECT(sinkpad));
1496 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1498 mm_player_t *player = NULL;
1499 MMHandleType attrs = 0;
1500 GstCaps *caps = NULL;
1501 gchar *caps_str = NULL;
1502 GstStructure *str = NULL;
1503 const gchar *name = NULL;
1504 GstElement *sinkbin = NULL;
1505 gboolean reusing = FALSE;
1506 gboolean caps_ret = TRUE;
1507 gchar *sink_pad_name = "sink";
1510 player = (mm_player_t*) data;
1513 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1514 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1516 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1520 caps_str = gst_caps_to_string(caps);
1522 /* LOGD("detected mimetype : %s", name); */
1523 if (strstr(name, "audio")) {
1524 if (player->pipeline->audiobin == NULL) {
1525 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1526 LOGE("failed to create audiobin. continuing without audio");
1530 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1531 LOGD("creating audiobin success");
1534 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1535 LOGD("reusing audiobin");
1536 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
1538 } else if (strstr(name, "video")) {
1539 /* 1. zero copy is updated at _decode_pad_added()
1540 * 2. NULL surface type is handled in _decode_pad_added() */
1541 LOGD("zero copy %d", player->set_mode.video_zc);
1542 if (player->pipeline->videobin == NULL) {
1543 int surface_type = 0;
1544 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1545 LOGD("display_surface_type (%d)", surface_type);
1547 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) {
1548 LOGD("mark video overlay for acquire");
1549 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1550 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1551 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1552 &player->video_overlay_resource)
1553 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1554 LOGE("could not mark video_overlay resource for acquire");
1559 player->interrupted_by_resource = FALSE;
1561 if (mm_resource_manager_commit(player->resource_manager) !=
1562 MM_RESOURCE_MANAGER_ERROR_NONE) {
1563 LOGE("could not acquire resources for video playing");
1567 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1568 LOGE("failed to create videobin. continuing without video");
1572 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1573 LOGD("creating videosink bin success");
1576 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1577 LOGD("re-using videobin");
1578 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
1580 } else if (strstr(name, "text")) {
1581 if (player->pipeline->textbin == NULL) {
1582 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1583 LOGE("failed to create text sink bin. continuing without text");
1587 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1588 player->textsink_linked = 1;
1589 LOGD("creating textsink bin success");
1591 if (!player->textsink_linked) {
1592 LOGD("re-using textbin");
1594 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1595 player->textsink_linked = 1;
1597 /* linked textbin exist which means that the external subtitle path exist already */
1598 LOGW("ignoring internal subtutle since external subtitle is available");
1601 sink_pad_name = "text_sink";
1603 LOGW("unknown mime type %s, ignoring it", name);
1607 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1610 LOGD("[handle: %p] success to create and link sink bin", player);
1612 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1613 * streaming task. if the task blocked, then buffer will not flow to the next element
1614 *(autoplugging element). so this is special hack for streaming. please try to remove it
1616 /* dec stream count. we can remove fakesink if it's zero */
1617 if (player->num_dynamic_pad)
1618 player->num_dynamic_pad--;
1620 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1622 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1623 __mmplayer_pipeline_complete(NULL, player);
1627 MMPLAYER_FREEIF(caps_str);
1630 gst_caps_unref(caps);
1632 /* flusing out new attributes */
1633 if (mm_attrs_commit_all(attrs))
1634 LOGE("failed to comit attributes");
1640 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int display_angle, int orientation, int *value)
1642 int required_angle = 0; /* Angle required for straight view */
1643 int rotation_angle = 0;
1645 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1646 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1648 /* Counter clockwise */
1649 switch (orientation) {
1654 required_angle = 270;
1657 required_angle = 180;
1660 required_angle = 90;
1664 rotation_angle = display_angle + required_angle;
1665 if (rotation_angle >= 360)
1666 rotation_angle -= 360;
1668 /* chech if supported or not */
1669 if (rotation_angle % 90) {
1670 LOGD("not supported rotation angle = %d", rotation_angle);
1674 switch (rotation_angle) {
1676 *value = MM_DISPLAY_ROTATION_NONE;
1679 *value = MM_DISPLAY_ROTATION_90;
1682 *value = MM_DISPLAY_ROTATION_180;
1685 *value = MM_DISPLAY_ROTATION_270;
1689 LOGD("setting rotation property value : %d", *value);
1695 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
1697 /* check video sinkbin is created */
1698 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1700 player->pipeline->videobin &&
1701 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1702 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1703 MM_ERROR_PLAYER_NOT_INITIALIZED);
1705 return MM_ERROR_NONE;
1709 __mmplayer_get_video_angle(mm_player_t* player, int *display_angle, int *orientation)
1711 int display_rotation = 0;
1712 gchar *org_orient = NULL;
1713 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1716 LOGE("cannot get content attribute");
1717 return MM_ERROR_PLAYER_INTERNAL;
1720 if (display_angle) {
1721 /* update user roation */
1722 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1724 /* Counter clockwise */
1725 switch (display_rotation) {
1726 case MM_DISPLAY_ROTATION_NONE:
1729 case MM_DISPLAY_ROTATION_90:
1730 *display_angle = 90;
1732 case MM_DISPLAY_ROTATION_180:
1733 *display_angle = 180;
1735 case MM_DISPLAY_ROTATION_270:
1736 *display_angle = 270;
1739 LOGW("wrong angle type : %d", display_rotation);
1742 LOGD("check user angle: %d", *display_angle);
1746 /* Counter clockwise */
1747 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1750 if (!strcmp(org_orient, "rotate-90"))
1752 else if (!strcmp(org_orient, "rotate-180"))
1754 else if (!strcmp(org_orient, "rotate-270"))
1757 LOGD("original rotation is %s", org_orient);
1759 LOGD("content_video_orientation get fail");
1762 LOGD("check orientation: %d", *orientation);
1765 return MM_ERROR_NONE;
1769 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
1771 int rotation_value = 0;
1772 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1773 int display_angle = 0;
1776 /* check video sinkbin is created */
1777 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1780 __mmplayer_get_video_angle(player, &display_angle, &orientations);
1782 /* get rotation value to set */
1783 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1784 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1785 LOGD("set video param : rotate %d", rotation_value);
1789 __mmplayer_video_param_set_display_visible(mm_player_t* player)
1791 MMHandleType attrs = 0;
1795 /* check video sinkbin is created */
1796 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1799 attrs = MMPLAYER_GET_ATTRS(player);
1800 MMPLAYER_RETURN_IF_FAIL(attrs);
1802 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1803 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1804 LOGD("set video param : visible %d", visible);
1808 __mmplayer_video_param_set_display_method(mm_player_t* player)
1810 MMHandleType attrs = 0;
1811 int display_method = 0;
1814 /* check video sinkbin is created */
1815 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1818 attrs = MMPLAYER_GET_ATTRS(player);
1819 MMPLAYER_RETURN_IF_FAIL(attrs);
1821 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1822 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1823 LOGD("set video param : method %d", display_method);
1826 __mmplayer_video_param_set_video_roi_area(mm_player_t* player)
1828 MMHandleType attrs = 0;
1829 void *handle = NULL;
1832 /* check video sinkbin is created */
1833 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1834 LOGW("There is no video sink");
1838 attrs = MMPLAYER_GET_ATTRS(player);
1839 MMPLAYER_RETURN_IF_FAIL(attrs);
1840 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1842 gst_video_overlay_set_video_roi_area(
1843 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1844 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1845 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1846 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1851 __mmplayer_video_param_set_roi_area(mm_player_t* player)
1853 MMHandleType attrs = 0;
1854 void *handle = NULL;
1858 int win_roi_width = 0;
1859 int win_roi_height = 0;
1862 /* check video sinkbin is created */
1863 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1864 LOGW("There is no video sink");
1868 attrs = MMPLAYER_GET_ATTRS(player);
1869 MMPLAYER_RETURN_IF_FAIL(attrs);
1871 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1874 /* It should be set after setting window */
1875 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1876 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1877 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1878 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1880 /* After setting window handle, set display roi area */
1881 gst_video_overlay_set_display_roi_area(
1882 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1883 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1884 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1885 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1889 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
1891 MMHandleType attrs = 0;
1892 void *handle = NULL;
1894 /* check video sinkbin is created */
1895 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1898 attrs = MMPLAYER_GET_ATTRS(player);
1899 MMPLAYER_RETURN_IF_FAIL(attrs);
1901 /* common case if using overlay surface */
1902 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1905 /* default is using wl_surface_id */
1906 unsigned int wl_surface_id = 0;
1907 wl_surface_id = *(int*)handle;
1908 LOGD("set video param : wl_surface_id %d", wl_surface_id);
1909 gst_video_overlay_set_wl_window_wl_surface_id(
1910 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1913 /* FIXIT : is it error case? */
1914 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1919 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
1921 bool update_all_param = FALSE;
1924 /* check video sinkbin is created */
1925 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1926 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1928 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1929 LOGE("can not find tizenwlsink");
1930 return MM_ERROR_PLAYER_INTERNAL;
1933 LOGD("param_name : %s", param_name);
1934 if (!g_strcmp0(param_name, "update_all_param"))
1935 update_all_param = TRUE;
1937 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1938 __mmplayer_video_param_set_display_overlay(player);
1939 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1940 __mmplayer_video_param_set_display_method(player);
1941 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1942 __mmplayer_video_param_set_display_visible(player);
1943 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1944 __mmplayer_video_param_set_display_rotation(player);
1945 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
1946 __mmplayer_video_param_set_roi_area(player);
1947 if (update_all_param)
1948 __mmplayer_video_param_set_video_roi_area(player);
1950 return MM_ERROR_NONE;
1954 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
1956 MMHandleType attrs = 0;
1957 int surface_type = 0;
1958 int ret = MM_ERROR_NONE;
1962 /* check video sinkbin is created */
1963 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1964 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1966 attrs = MMPLAYER_GET_ATTRS(player);
1968 LOGE("cannot get content attribute");
1969 return MM_ERROR_PLAYER_INTERNAL;
1971 LOGD("param_name : %s", param_name);
1973 /* update display surface */
1974 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
1975 LOGD("check display surface type attribute: %d", surface_type);
1977 /* configuring display */
1978 switch (surface_type) {
1979 case MM_DISPLAY_SURFACE_OVERLAY:
1981 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
1982 if (ret != MM_ERROR_NONE)
1990 return MM_ERROR_NONE;
1994 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
1996 gboolean disable_overlay = FALSE;
1997 mm_player_t* player = (mm_player_t*) hplayer;
1998 int ret = MM_ERROR_NONE;
2001 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2002 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2003 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2004 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2006 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2007 LOGW("Display control is not supported");
2008 return MM_ERROR_PLAYER_INTERNAL;
2011 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2013 if (audio_only == (bool)disable_overlay) {
2014 LOGE("It's the same with current setting: (%d)", audio_only);
2015 return MM_ERROR_NONE;
2019 LOGE("disable overlay");
2020 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2022 /* release overlay resource */
2023 if (player->video_overlay_resource != NULL) {
2024 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2025 player->video_overlay_resource);
2026 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2027 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
2030 player->video_overlay_resource = NULL;
2033 ret = mm_resource_manager_commit(player->resource_manager);
2034 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2035 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
2039 /* mark video overlay for acquire */
2040 if (player->video_overlay_resource == NULL) {
2041 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2042 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2043 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2044 &player->video_overlay_resource);
2045 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2046 LOGE("could not prepare for video_overlay resource\n");
2051 player->interrupted_by_resource = FALSE;
2052 /* acquire resources for video overlay */
2053 ret = mm_resource_manager_commit(player->resource_manager);
2054 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2055 LOGE("could not acquire resources for video playing\n");
2059 LOGD("enable overlay");
2060 __mmplayer_video_param_set_display_overlay(player);
2061 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2066 return MM_ERROR_NONE;
2070 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2072 mm_player_t* player = (mm_player_t*) hplayer;
2073 gboolean disable_overlay = FALSE;
2077 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2078 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2079 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2080 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2081 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2083 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2084 LOGW("Display control is not supported");
2085 return MM_ERROR_PLAYER_INTERNAL;
2088 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2090 *paudio_only = (bool)(disable_overlay);
2092 LOGD("audio_only : %d", *paudio_only);
2096 return MM_ERROR_NONE;
2100 __mmplayer_gst_element_link_bucket(GList* element_bucket)
2102 GList* bucket = element_bucket;
2103 MMPlayerGstElement* element = NULL;
2104 MMPlayerGstElement* prv_element = NULL;
2105 gint successful_link_count = 0;
2109 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2111 prv_element = (MMPlayerGstElement*)bucket->data;
2112 bucket = bucket->next;
2114 for (; bucket; bucket = bucket->next) {
2115 element = (MMPlayerGstElement*)bucket->data;
2117 if (element && element->gst) {
2118 if (prv_element && prv_element->gst) {
2119 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2120 LOGD("linking [%s] to [%s] success\n",
2121 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2122 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2123 successful_link_count++;
2125 LOGD("linking [%s] to [%s] failed\n",
2126 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2127 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2133 prv_element = element;
2138 return successful_link_count;
2142 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
2144 GList* bucket = element_bucket;
2145 MMPlayerGstElement* element = NULL;
2146 int successful_add_count = 0;
2150 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2151 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2153 for (; bucket; bucket = bucket->next) {
2154 element = (MMPlayerGstElement*)bucket->data;
2156 if (element && element->gst) {
2157 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2158 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
2159 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2160 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2163 successful_add_count++;
2169 return successful_add_count;
2172 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2174 mm_player_t *player = (mm_player_t*) data;
2175 GstCaps *caps = NULL;
2176 GstStructure *str = NULL;
2178 gboolean caps_ret = TRUE;
2182 MMPLAYER_RETURN_IF_FAIL(pad);
2183 MMPLAYER_RETURN_IF_FAIL(unused);
2184 MMPLAYER_RETURN_IF_FAIL(data);
2186 caps = gst_pad_get_current_caps(pad);
2190 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2194 LOGD("name = %s", name);
2196 if (strstr(name, "audio")) {
2197 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2199 if (player->audio_stream_changed_cb) {
2200 LOGE("call the audio stream changed cb");
2201 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2203 } else if (strstr(name, "video")) {
2204 if ((name = gst_structure_get_string(str, "format")))
2205 player->set_mode.video_zc = name[0] == 'S';
2207 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2209 if (player->video_stream_changed_cb) {
2210 LOGE("call the video stream changed cb");
2211 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2214 LOGW("invalid caps info");
2219 gst_caps_unref(caps);
2229 * This function is to create audio pipeline for playing.
2231 * @param player [in] handle of player
2233 * @return This function returns zero on success.
2235 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_sink_bin
2237 /* macro for code readability. just for sinkbin-creation functions */
2238 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2240 x_bin[x_id].id = x_id;\
2241 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2242 if (!x_bin[x_id].gst) {\
2243 LOGE("failed to create %s \n", x_factory);\
2246 if (x_player->ini.set_dump_element_flag)\
2247 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2250 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2254 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
2259 MMPLAYER_RETURN_IF_FAIL(player);
2261 if (player->audio_stream_buff_list) {
2262 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2263 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2266 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2267 __mmplayer_audio_stream_send_data(player, tmp);
2270 g_free(tmp->pcm_data);
2274 g_list_free(player->audio_stream_buff_list);
2275 player->audio_stream_buff_list = NULL;
2282 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
2284 MMPlayerAudioStreamDataType audio_stream = { 0, };
2287 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2289 audio_stream.bitrate = a_buffer->bitrate;
2290 audio_stream.channel = a_buffer->channel;
2291 audio_stream.depth = a_buffer->depth;
2292 audio_stream.is_little_endian = a_buffer->is_little_endian;
2293 audio_stream.channel_mask = a_buffer->channel_mask;
2294 audio_stream.data_size = a_buffer->data_size;
2295 audio_stream.data = a_buffer->pcm_data;
2297 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
2298 player->audio_stream_render_cb(&audio_stream, player->audio_stream_cb_user_param);
2304 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
2306 mm_player_t* player = (mm_player_t*) data;
2311 gint endianness = 0;
2312 guint64 channel_mask = 0;
2313 void *a_data = NULL;
2315 mm_player_audio_stream_buff_t *a_buffer = NULL;
2316 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2320 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2322 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2323 a_data = mapinfo.data;
2324 a_size = mapinfo.size;
2326 GstCaps *caps = gst_pad_get_current_caps(pad);
2327 GstStructure *structure = gst_caps_get_structure(caps, 0);
2329 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2330 gst_structure_get_int(structure, "rate", &rate);
2331 gst_structure_get_int(structure, "channels", &channel);
2332 gst_structure_get_int(structure, "depth", &depth);
2333 gst_structure_get_int(structure, "endianness", &endianness);
2334 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2335 gst_caps_unref(GST_CAPS(caps));
2337 /* In case of the sync is false, use buffer list. *
2338 * The num of buffer list depends on the num of audio channels */
2339 if (player->audio_stream_buff_list) {
2340 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2341 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2343 if (channel_mask == tmp->channel_mask) {
2344 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2345 if (tmp->data_size + a_size < tmp->buff_size) {
2346 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2347 tmp->data_size += a_size;
2349 /* send data to client */
2350 __mmplayer_audio_stream_send_data(player, tmp);
2352 if (a_size > tmp->buff_size) {
2353 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2354 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2355 if (tmp->pcm_data == NULL) {
2356 LOGE("failed to realloc data.");
2359 tmp->buff_size = a_size;
2361 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2362 memcpy(tmp->pcm_data, a_data, a_size);
2363 tmp->data_size = a_size;
2368 LOGE("data is empty in list.");
2374 /* create new audio stream data */
2375 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
2376 if (a_buffer == NULL) {
2377 LOGE("failed to alloc data.");
2380 a_buffer->bitrate = rate;
2381 a_buffer->channel = channel;
2382 a_buffer->depth = depth;
2383 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
2384 a_buffer->channel_mask = channel_mask;
2385 a_buffer->data_size = a_size;
2387 if (!player->audio_stream_sink_sync) {
2388 /* If sync is FALSE, use buffer list to reduce the IPC. */
2389 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2390 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
2391 if (a_buffer->pcm_data == NULL) {
2392 LOGE("failed to alloc data.");
2396 memcpy(a_buffer->pcm_data, a_data, a_size);
2397 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2398 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2400 /* If sync is TRUE, send data directly. */
2401 a_buffer->pcm_data = a_data;
2402 __mmplayer_audio_stream_send_data(player, a_buffer);
2407 gst_buffer_unmap(buffer, &mapinfo);
2412 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2414 mm_player_t* player = (mm_player_t*)data;
2415 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
2416 GstPad* sinkpad = NULL;
2417 GstElement *queue = NULL, *sink = NULL;
2420 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2422 queue = gst_element_factory_make("queue", NULL);
2423 if (queue == NULL) {
2424 LOGD("fail make queue\n");
2428 sink = gst_element_factory_make("fakesink", NULL);
2430 LOGD("fail make fakesink\n");
2434 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2436 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2437 LOGW("failed to link queue & sink\n");
2441 sinkpad = gst_element_get_static_pad(queue, "sink");
2443 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2444 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
2448 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
2450 gst_object_unref(sinkpad);
2451 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
2452 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2454 gst_element_set_state(sink, GST_STATE_PAUSED);
2455 gst_element_set_state(queue, GST_STATE_PAUSED);
2457 __mmplayer_add_signal_connection(player,
2459 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2461 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2468 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
2470 gst_object_unref(GST_OBJECT(queue));
2474 gst_object_unref(GST_OBJECT(sink));
2478 gst_object_unref(GST_OBJECT(sinkpad));
2485 void __mmplayer_gst_set_pulsesink_property(mm_player_t* player, MMHandleType attrs)
2487 #define MAX_PROPS_LEN 128
2488 gint latency_mode = 0;
2489 gchar *stream_type = NULL;
2490 gchar *latency = NULL;
2492 gchar stream_props[MAX_PROPS_LEN] = {0,};
2493 GstStructure *props = NULL;
2496 * It should be set after player creation through attribute.
2497 * But, it can not be changed during playing.
2500 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2502 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
2503 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
2506 LOGE("stream_type is null.");
2508 if (player->sound.focus_id)
2509 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
2510 stream_type, stream_id, player->sound.focus_id);
2512 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
2513 stream_type, stream_id);
2514 props = gst_structure_from_string(stream_props, NULL);
2515 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2516 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].",
2517 stream_type, stream_id, player->sound.focus_id, stream_props);
2518 gst_structure_free(props);
2521 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2523 switch (latency_mode) {
2524 case AUDIO_LATENCY_MODE_LOW:
2525 latency = g_strndup("low", 3);
2527 case AUDIO_LATENCY_MODE_MID:
2528 latency = g_strndup("mid", 3);
2530 case AUDIO_LATENCY_MODE_HIGH:
2531 latency = g_strndup("high", 4);
2535 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2539 LOGD("audiosink property - latency=%s", latency);
2546 void __mmplayer_gst_set_openalsink_property(mm_player_t* player)
2548 MMPlayerGstElement *audiobin = NULL;
2551 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2553 audiobin = player->pipeline->audiobin;
2555 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2556 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2557 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2559 if (player->video360_yaw_radians <= M_PI &&
2560 player->video360_yaw_radians >= -M_PI &&
2561 player->video360_pitch_radians <= M_PI_2 &&
2562 player->video360_pitch_radians >= -M_PI_2) {
2563 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2564 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
2565 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
2566 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2567 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2568 "source-orientation-y", player->video360_metadata.init_view_heading,
2569 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2576 __mmplayer_gst_fill_audio_bucket(mm_player_t *player, GList **bucket)
2578 MMPlayerGstElement *audiobin = NULL;
2579 MMHandleType attrs = 0;
2580 GList *element_bucket = NULL;
2581 GstCaps *acaps = NULL;
2582 GstPad *sink_pad = NULL;
2585 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2586 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2588 audiobin = player->pipeline->audiobin;
2589 attrs = MMPLAYER_GET_ATTRS(player);
2592 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2594 /* replaygain volume */
2595 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2596 if (player->sound.rg_enable)
2597 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2599 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2602 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2604 if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2605 gchar *dst_format = NULL;
2607 int dst_samplerate = 0;
2608 int dst_channels = 0;
2609 GstCaps *caps = NULL;
2610 char *caps_str = NULL;
2612 /* get conf. values */
2613 mm_attrs_multiple_get(player->attrs, NULL,
2614 "pcm_audioformat", &dst_format, &dst_len,
2615 "pcm_extraction_samplerate", &dst_samplerate,
2616 "pcm_extraction_channels", &dst_channels,
2619 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2622 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2623 caps = gst_caps_new_simple("audio/x-raw",
2624 "format", G_TYPE_STRING, dst_format,
2625 "rate", G_TYPE_INT, dst_samplerate,
2626 "channels", G_TYPE_INT, dst_channels,
2629 caps_str = gst_caps_to_string(caps);
2630 LOGD("new caps : %s", caps_str);
2632 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2635 gst_caps_unref(caps);
2636 MMPLAYER_FREEIF(caps_str);
2638 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2640 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2642 /* raw pad handling signal, audiosink will be added after getting signal */
2643 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2644 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2648 /* normal playback */
2651 /* for logical volume control */
2652 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2653 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2655 if (player->sound.mute) {
2656 LOGD("mute enabled");
2657 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2660 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2662 /* audio effect element. if audio effect is enabled */
2663 if ((strcmp(player->ini.audioeffect_element, ""))
2665 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2666 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2668 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2670 if ((!player->bypass_audio_effect)
2671 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2672 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2673 if (!_mmplayer_audio_effect_custom_apply(player))
2674 LOGI("apply audio effect(custom) setting success");
2678 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2679 && (player->set_mode.rich_audio))
2680 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2683 /* create audio sink */
2684 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2685 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2686 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2688 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2689 if (player->is_360_feature_enabled &&
2690 player->is_content_spherical &&
2692 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2693 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2694 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2696 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2698 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2700 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2701 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2702 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2703 gst_caps_unref(acaps);
2705 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2707 player->is_openal_plugin_used = TRUE;
2709 if (player->is_360_feature_enabled && player->is_content_spherical)
2710 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2711 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2714 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2715 (player->videodec_linked && player->ini.use_system_clock)) {
2716 LOGD("system clock will be used.");
2717 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2720 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2721 __mmplayer_gst_set_pulsesink_property(player, attrs);
2722 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2723 __mmplayer_gst_set_openalsink_property(player);
2726 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2727 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2729 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2730 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2731 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2732 gst_object_unref(GST_OBJECT(sink_pad));
2734 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2737 *bucket = element_bucket;
2740 return MM_ERROR_NONE;
2743 g_list_free(element_bucket);
2747 return MM_ERROR_PLAYER_INTERNAL;
2751 __mmplayer_gst_create_audio_sink_bin(mm_player_t* player)
2753 MMPlayerGstElement *first_element = NULL;
2754 MMPlayerGstElement *audiobin = NULL;
2756 GstPad *ghostpad = NULL;
2757 GList *element_bucket = NULL;
2761 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2764 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2766 LOGE("failed to allocate memory for audiobin");
2767 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2771 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2772 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2773 if (!audiobin[MMPLAYER_A_BIN].gst) {
2774 LOGE("failed to create audiobin");
2779 player->pipeline->audiobin = audiobin;
2781 /* create audio filters and audiosink */
2782 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2785 /* adding created elements to bin */
2786 LOGD("adding created elements to bin");
2787 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2790 /* linking elements in the bucket by added order. */
2791 LOGD("Linking elements in the bucket by added order.");
2792 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2795 /* get first element's sinkpad for creating ghostpad */
2796 first_element = (MMPlayerGstElement *)element_bucket->data;
2797 if (!first_element) {
2798 LOGE("failed to get first elem");
2802 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2804 LOGE("failed to get pad from first element of audiobin");
2808 ghostpad = gst_ghost_pad_new("sink", pad);
2810 LOGE("failed to create ghostpad");
2814 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2815 LOGE("failed to add ghostpad to audiobin");
2819 gst_object_unref(pad);
2821 g_list_free(element_bucket);
2824 return MM_ERROR_NONE;
2827 LOGD("ERROR : releasing audiobin");
2830 gst_object_unref(GST_OBJECT(pad));
2833 gst_object_unref(GST_OBJECT(ghostpad));
2836 g_list_free(element_bucket);
2838 /* release element which are not added to bin */
2839 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2840 /* NOTE : skip bin */
2841 if (audiobin[i].gst) {
2842 GstObject* parent = NULL;
2843 parent = gst_element_get_parent(audiobin[i].gst);
2846 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2847 audiobin[i].gst = NULL;
2849 gst_object_unref(GST_OBJECT(parent));
2853 /* release audiobin with it's childs */
2854 if (audiobin[MMPLAYER_A_BIN].gst)
2855 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2857 MMPLAYER_FREEIF(audiobin);
2859 player->pipeline->audiobin = NULL;
2861 return MM_ERROR_PLAYER_INTERNAL;
2864 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
2866 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2869 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
2871 int ret = MM_ERROR_NONE;
2873 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2874 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2876 MMPLAYER_VIDEO_BO_LOCK(player);
2878 if (player->video_bo_list) {
2879 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2880 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
2881 if (tmp && tmp->bo == bo) {
2883 LOGD("release bo %p", bo);
2884 tbm_bo_unref(tmp->bo);
2885 MMPLAYER_VIDEO_BO_UNLOCK(player);
2886 MMPLAYER_VIDEO_BO_SIGNAL(player);
2891 /* hw codec is running or the list was reset for DRC. */
2892 LOGW("there is no bo list.");
2894 MMPLAYER_VIDEO_BO_UNLOCK(player);
2896 LOGW("failed to find bo %p", bo);
2901 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
2906 MMPLAYER_RETURN_IF_FAIL(player);
2908 MMPLAYER_VIDEO_BO_LOCK(player);
2909 if (player->video_bo_list) {
2910 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2911 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2912 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
2915 tbm_bo_unref(tmp->bo);
2919 g_list_free(player->video_bo_list);
2920 player->video_bo_list = NULL;
2922 player->video_bo_size = 0;
2923 MMPLAYER_VIDEO_BO_UNLOCK(player);
2930 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
2933 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2934 gboolean ret = TRUE;
2936 /* check DRC, if it is, destroy the prev bo list to create again */
2937 if (player->video_bo_size != size) {
2938 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
2939 __mmplayer_video_stream_destroy_bo_list(player);
2940 player->video_bo_size = size;
2943 MMPLAYER_VIDEO_BO_LOCK(player);
2945 if ((!player->video_bo_list) ||
2946 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
2948 /* create bo list */
2950 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
2952 if (player->video_bo_list) {
2953 /* if bo list did not created all, try it again. */
2954 idx = g_list_length(player->video_bo_list);
2955 LOGD("bo list exist(len: %d)", idx);
2958 for (; idx < player->ini.num_of_video_bo; idx++) {
2959 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
2961 LOGE("Fail to alloc bo_info.");
2964 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
2966 LOGE("Fail to tbm_bo_alloc.");
2970 bo_info->used = FALSE;
2971 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
2974 /* update video num buffers */
2975 player->video_num_buffers = idx;
2976 if (idx == player->ini.num_of_video_bo)
2977 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
2980 MMPLAYER_VIDEO_BO_UNLOCK(player);
2984 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
2988 /* get bo from list*/
2989 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2990 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
2991 if (tmp && (tmp->used == FALSE)) {
2992 LOGD("found bo %p to use", tmp->bo);
2994 MMPLAYER_VIDEO_BO_UNLOCK(player);
2995 return tbm_bo_ref(tmp->bo);
2999 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3000 MMPLAYER_VIDEO_BO_UNLOCK(player);
3004 if (player->ini.video_bo_timeout <= 0) {
3005 MMPLAYER_VIDEO_BO_WAIT(player);
3007 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
3008 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3015 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3017 mm_player_t* player = (mm_player_t*)data;
3019 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3021 /* send prerolled pkt */
3022 player->video_stream_prerolled = FALSE;
3024 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3026 /* not to send prerolled pkt again */
3027 player->video_stream_prerolled = TRUE;
3031 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3033 mm_player_t* player = (mm_player_t*)data;
3034 MMPlayerVideoStreamDataType *stream = NULL;
3035 GstMemory *mem = NULL;
3038 MMPLAYER_RETURN_IF_FAIL(player);
3039 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3041 if (player->video_stream_prerolled) {
3042 player->video_stream_prerolled = FALSE;
3043 LOGD("skip the prerolled pkt not to send it again");
3047 /* clear stream data structure */
3048 stream = __mmplayer_create_stream_from_pad(pad);
3050 LOGE("failed to alloc stream");
3054 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3056 /* set size and timestamp */
3057 mem = gst_buffer_peek_memory(buffer, 0);
3058 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3059 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3061 /* check zero-copy */
3062 if (player->set_mode.video_zc &&
3063 player->set_mode.media_packet_video_stream &&
3064 gst_is_tizen_memory(mem)) {
3065 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3066 stream->internal_buffer = gst_buffer_ref(buffer);
3067 } else { /* sw codec */
3068 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3071 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3075 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3076 LOGE("failed to send video stream data.");
3083 LOGE("release video stream resource.");
3084 if (gst_is_tizen_memory(mem)) {
3086 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3088 tbm_bo_unref(stream->bo[i]);
3091 /* unref gst buffer */
3092 if (stream->internal_buffer)
3093 gst_buffer_unref(stream->internal_buffer);
3096 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3103 __mmplayer_gst_set_video360_property(mm_player_t *player)
3105 MMPlayerGstElement *videobin = NULL;
3108 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3110 videobin = player->pipeline->videobin;
3112 /* Set spatial media metadata and/or user settings to the element.
3114 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3115 "projection-type", player->video360_metadata.projection_type, NULL);
3117 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3118 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3120 if (player->video360_metadata.full_pano_width_pixels &&
3121 player->video360_metadata.full_pano_height_pixels &&
3122 player->video360_metadata.cropped_area_image_width &&
3123 player->video360_metadata.cropped_area_image_height) {
3124 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3125 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3126 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3127 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3128 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3129 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3130 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3134 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3135 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3136 "horizontal-fov", player->video360_horizontal_fov,
3137 "vertical-fov", player->video360_vertical_fov, NULL);
3140 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3141 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3142 "zoom", 1.0f / player->video360_zoom, NULL);
3145 if (player->video360_yaw_radians <= M_PI &&
3146 player->video360_yaw_radians >= -M_PI &&
3147 player->video360_pitch_radians <= M_PI_2 &&
3148 player->video360_pitch_radians >= -M_PI_2) {
3149 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3150 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
3151 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
3152 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3153 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3154 "pose-yaw", player->video360_metadata.init_view_heading,
3155 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3158 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3159 "passthrough", !player->is_video360_enabled, NULL);
3166 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3168 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3169 GList *element_bucket = NULL;
3172 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3174 /* create video360 filter */
3175 if (player->is_360_feature_enabled && player->is_content_spherical) {
3176 LOGD("create video360 element");
3177 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3178 __mmplayer_gst_set_video360_property(player);
3182 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3183 LOGD("skip creating the videoconv and rotator");
3184 return MM_ERROR_NONE;
3187 /* in case of sw codec & overlay surface type, except 360 playback.
3188 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3189 LOGD("create video converter: %s", video_csc);
3190 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3192 /* set video rotator */
3193 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
3196 *bucket = element_bucket;
3198 return MM_ERROR_NONE;
3200 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3201 g_list_free(element_bucket);
3205 return MM_ERROR_PLAYER_INTERNAL;
3209 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3211 gchar *factory_name = NULL;
3213 switch (surface_type) {
3214 case MM_DISPLAY_SURFACE_OVERLAY:
3215 if (strlen(player->ini.videosink_element_overlay) > 0)
3216 factory_name = player->ini.videosink_element_overlay;
3218 case MM_DISPLAY_SURFACE_REMOTE:
3219 case MM_DISPLAY_SURFACE_NULL:
3220 if (strlen(player->ini.videosink_element_fake) > 0)
3221 factory_name = player->ini.videosink_element_fake;
3224 LOGE("unidentified surface type");
3228 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3229 return factory_name;
3233 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3235 gchar *factory_name = NULL;
3236 MMPlayerGstElement *videobin = NULL;
3241 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3243 videobin = player->pipeline->videobin;
3244 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3246 attrs = MMPLAYER_GET_ATTRS(player);
3248 LOGE("cannot get content attribute");
3249 return MM_ERROR_PLAYER_INTERNAL;
3252 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3253 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3254 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3256 /* support shard memory with S/W codec on HawkP */
3257 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3258 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3259 "use-tbm", use_tbm, NULL);
3263 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3264 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3267 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3269 LOGD("disable last-sample");
3270 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3273 if (player->set_mode.media_packet_video_stream) {
3275 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3276 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3277 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3279 __mmplayer_add_signal_connection(player,
3280 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3281 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3283 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3286 __mmplayer_add_signal_connection(player,
3287 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3288 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3290 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3294 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3295 return MM_ERROR_PLAYER_INTERNAL;
3297 if (videobin[MMPLAYER_V_SINK].gst) {
3298 GstPad *sink_pad = NULL;
3299 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3301 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3302 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3303 gst_object_unref(GST_OBJECT(sink_pad));
3305 LOGE("failed to get sink pad from videosink");
3309 return MM_ERROR_NONE;
3314 * - video overlay surface(arm/x86) : tizenwlsink
3317 __mmplayer_gst_create_video_sink_bin(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
3320 GList *element_bucket = NULL;
3321 MMPlayerGstElement *first_element = NULL;
3322 MMPlayerGstElement *videobin = NULL;
3323 gchar *videosink_factory_name = NULL;
3326 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3329 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3331 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3333 player->pipeline->videobin = videobin;
3336 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3337 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3338 if (!videobin[MMPLAYER_V_BIN].gst) {
3339 LOGE("failed to create videobin");
3343 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3346 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3347 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3349 /* additional setting for sink plug-in */
3350 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3351 LOGE("failed to set video property");
3355 /* store it as it's sink element */
3356 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3358 /* adding created elements to bin */
3359 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3360 LOGE("failed to add elements");
3364 /* Linking elements in the bucket by added order */
3365 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3366 LOGE("failed to link elements");
3370 /* get first element's sinkpad for creating ghostpad */
3371 first_element = (MMPlayerGstElement *)element_bucket->data;
3372 if (!first_element) {
3373 LOGE("failed to get first element from bucket");
3377 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3379 LOGE("failed to get pad from first element");
3383 /* create ghostpad */
3384 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3385 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3386 LOGE("failed to add ghostpad to videobin");
3389 gst_object_unref(pad);
3391 /* done. free allocated variables */
3392 g_list_free(element_bucket);
3396 return MM_ERROR_NONE;
3399 LOGE("ERROR : releasing videobin");
3400 g_list_free(element_bucket);
3403 gst_object_unref(GST_OBJECT(pad));
3405 /* release videobin with it's childs */
3406 if (videobin[MMPLAYER_V_BIN].gst)
3407 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3409 MMPLAYER_FREEIF(videobin);
3410 player->pipeline->videobin = NULL;
3412 return MM_ERROR_PLAYER_INTERNAL;
3415 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
3417 GList *element_bucket = NULL;
3418 MMPlayerGstElement *textbin = player->pipeline->textbin;
3420 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3421 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3422 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3423 "signal-handoffs", FALSE,
3426 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3427 __mmplayer_add_signal_connection(player,
3428 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3429 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3431 G_CALLBACK(__mmplayer_update_subtitle),
3434 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3435 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3437 if (!player->play_subtitle) {
3438 LOGD("add textbin sink as sink element of whole pipeline.\n");
3439 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3442 /* adding created elements to bin */
3443 LOGD("adding created elements to bin\n");
3444 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3445 LOGE("failed to add elements\n");
3449 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3450 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3451 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3453 /* linking elements in the bucket by added order. */
3454 LOGD("Linking elements in the bucket by added order.\n");
3455 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3456 LOGE("failed to link elements\n");
3460 /* done. free allocated variables */
3461 g_list_free(element_bucket);
3463 if (textbin[MMPLAYER_T_QUEUE].gst) {
3465 GstPad *ghostpad = NULL;
3467 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3469 LOGE("failed to get sink pad of text queue");
3473 ghostpad = gst_ghost_pad_new("text_sink", pad);
3474 gst_object_unref(pad);
3477 LOGE("failed to create ghostpad of textbin\n");
3481 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3482 LOGE("failed to add ghostpad to textbin\n");
3483 gst_object_unref(ghostpad);
3488 return MM_ERROR_NONE;
3491 g_list_free(element_bucket);
3493 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3494 LOGE("remove textbin sink from sink list");
3495 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3498 /* release element at __mmplayer_gst_create_text_sink_bin */
3499 return MM_ERROR_PLAYER_INTERNAL;
3502 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
3504 MMPlayerGstElement *textbin = NULL;
3505 GList *element_bucket = NULL;
3506 int surface_type = 0;
3511 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3514 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3516 LOGE("failed to allocate memory for textbin\n");
3517 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3521 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3522 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3523 if (!textbin[MMPLAYER_T_BIN].gst) {
3524 LOGE("failed to create textbin\n");
3529 player->pipeline->textbin = textbin;
3532 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3533 LOGD("surface type for subtitle : %d", surface_type);
3534 switch (surface_type) {
3535 case MM_DISPLAY_SURFACE_OVERLAY:
3536 case MM_DISPLAY_SURFACE_NULL:
3537 case MM_DISPLAY_SURFACE_REMOTE:
3538 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3539 LOGE("failed to make plain text elements\n");
3550 return MM_ERROR_NONE;
3554 LOGD("ERROR : releasing textbin\n");
3556 g_list_free(element_bucket);
3558 /* release signal */
3559 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3561 /* release element which are not added to bin */
3562 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3563 /* NOTE : skip bin */
3564 if (textbin[i].gst) {
3565 GstObject* parent = NULL;
3566 parent = gst_element_get_parent(textbin[i].gst);
3569 gst_object_unref(GST_OBJECT(textbin[i].gst));
3570 textbin[i].gst = NULL;
3572 gst_object_unref(GST_OBJECT(parent));
3577 /* release textbin with it's childs */
3578 if (textbin[MMPLAYER_T_BIN].gst)
3579 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3581 MMPLAYER_FREEIF(player->pipeline->textbin);
3582 player->pipeline->textbin = NULL;
3585 return MM_ERROR_PLAYER_INTERNAL;
3590 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
3592 MMPlayerGstElement* mainbin = NULL;
3593 MMPlayerGstElement* textbin = NULL;
3594 MMHandleType attrs = 0;
3595 GstElement *subsrc = NULL;
3596 GstElement *subparse = NULL;
3597 gchar *subtitle_uri = NULL;
3598 const gchar *charset = NULL;
3604 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3606 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3608 mainbin = player->pipeline->mainbin;
3610 attrs = MMPLAYER_GET_ATTRS(player);
3612 LOGE("cannot get content attribute\n");
3613 return MM_ERROR_PLAYER_INTERNAL;
3616 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3617 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3618 LOGE("subtitle uri is not proper filepath.\n");
3619 return MM_ERROR_PLAYER_INVALID_URI;
3622 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3623 LOGE("failed to get storage info of subtitle path");
3624 return MM_ERROR_PLAYER_INVALID_URI;
3627 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
3629 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3630 player->subtitle_language_list = NULL;
3631 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3633 /* create the subtitle source */
3634 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3636 LOGE("failed to create filesrc element\n");
3639 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3641 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3642 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3644 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3645 LOGW("failed to add queue\n");
3646 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3647 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3648 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3653 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3655 LOGE("failed to create subparse element\n");
3659 charset = util_get_charset(subtitle_uri);
3661 LOGD("detected charset is %s\n", charset);
3662 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3665 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3666 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3668 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3669 LOGW("failed to add subparse\n");
3670 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3671 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3672 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3676 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3677 LOGW("failed to link subsrc and subparse\n");
3681 player->play_subtitle = TRUE;
3682 player->adjust_subtitle_pos = 0;
3684 LOGD("play subtitle using subtitle file\n");
3686 if (player->pipeline->textbin == NULL) {
3687 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3688 LOGE("failed to create text sink bin. continuing without text\n");
3692 textbin = player->pipeline->textbin;
3694 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3695 LOGW("failed to add textbin\n");
3697 /* release signal */
3698 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3700 /* release textbin with it's childs */
3701 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3702 MMPLAYER_FREEIF(player->pipeline->textbin);
3703 player->pipeline->textbin = textbin = NULL;
3707 LOGD("link text input selector and textbin ghost pad");
3709 player->textsink_linked = 1;
3710 player->external_text_idx = 0;
3711 LOGI("textsink is linked");
3713 textbin = player->pipeline->textbin;
3714 LOGD("text bin has been created. reuse it.");
3715 player->external_text_idx = 1;
3718 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3719 LOGW("failed to link subparse and textbin\n");
3723 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3725 LOGE("failed to get sink pad from textsink to probe data");
3729 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3730 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3732 gst_object_unref(pad);
3735 /* create dot. for debugging */
3736 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3739 return MM_ERROR_NONE;
3742 /* release text pipeline resource */
3743 player->textsink_linked = 0;
3745 /* release signal */
3746 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3748 if (player->pipeline->textbin) {
3749 LOGE("remove textbin");
3751 /* release textbin with it's childs */
3752 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3753 MMPLAYER_FREEIF(player->pipeline->textbin);
3754 player->pipeline->textbin = NULL;
3758 /* release subtitle elem */
3759 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3760 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3762 return MM_ERROR_PLAYER_INTERNAL;
3766 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3768 mm_player_t* player = (mm_player_t*) data;
3769 MMMessageParamType msg = {0, };
3770 GstClockTime duration = 0;
3771 gpointer text = NULL;
3772 guint text_size = 0;
3773 gboolean ret = TRUE;
3774 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3778 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3779 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3781 if (player->is_subtitle_force_drop) {
3782 LOGW("subtitle is dropped forcedly.");
3786 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3787 text = mapinfo.data;
3788 text_size = mapinfo.size;
3789 duration = GST_BUFFER_DURATION(buffer);
3791 if (player->set_mode.subtitle_off) {
3792 LOGD("subtitle is OFF.\n");
3796 if (!text || (text_size == 0)) {
3797 LOGD("There is no subtitle to be displayed.\n");
3801 msg.data = (void *) text;
3802 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3804 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
3806 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3807 gst_buffer_unmap(buffer, &mapinfo);
3814 static GstPadProbeReturn
3815 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3817 mm_player_t *player = (mm_player_t *) u_data;
3818 GstClockTime cur_timestamp = 0;
3819 gint64 adjusted_timestamp = 0;
3820 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3822 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3824 if (player->set_mode.subtitle_off) {
3825 LOGD("subtitle is OFF.\n");
3829 if (player->adjust_subtitle_pos == 0) {
3830 LOGD("nothing to do");
3834 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3835 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3837 if (adjusted_timestamp < 0) {
3838 LOGD("adjusted_timestamp under zero");
3843 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3844 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3845 GST_TIME_ARGS(cur_timestamp),
3846 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3848 return GST_PAD_PROBE_OK;
3850 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
3854 /* check player and subtitlebin are created */
3855 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3856 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3858 if (position == 0) {
3859 LOGD("nothing to do\n");
3861 return MM_ERROR_NONE;
3865 case MM_PLAYER_POS_FORMAT_TIME:
3867 /* check current postion */
3868 player->adjust_subtitle_pos = position;
3870 LOGD("save adjust_subtitle_pos in player") ;
3876 LOGW("invalid format.\n");
3878 return MM_ERROR_INVALID_ARGUMENT;
3884 return MM_ERROR_NONE;
3888 * This function is to create audio or video pipeline for playing.
3890 * @param player [in] handle of player
3892 * @return This function returns zero on success.
3897 __mmplayer_gst_create_pipeline(mm_player_t* player)
3899 int ret = MM_ERROR_NONE;
3900 MMPlayerGstElement *mainbin = NULL;
3901 MMHandleType attrs = 0;
3904 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3906 /* get profile attribute */
3907 attrs = MMPLAYER_GET_ATTRS(player);
3909 LOGE("failed to get content attribute");
3913 /* create pipeline handles */
3914 if (player->pipeline) {
3915 LOGE("pipeline should be released before create new one");
3919 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
3920 if (player->pipeline == NULL)
3923 /* create mainbin */
3924 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
3925 if (mainbin == NULL)
3928 /* create pipeline */
3929 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3930 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3931 if (!mainbin[MMPLAYER_M_PIPE].gst) {
3932 LOGE("failed to create pipeline");
3937 player->pipeline->mainbin = mainbin;
3939 /* create the source and decoder elements */
3940 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3941 ret = __mmplayer_gst_build_es_pipeline(player);
3943 ret = __mmplayer_gst_build_pipeline(player);
3945 if (ret != MM_ERROR_NONE) {
3946 LOGE("failed to create some elements");
3950 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
3951 if (__mmplayer_check_subtitle(player)) {
3952 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE)
3953 LOGE("failed to create text pipeline");
3957 ret = __mmplayer_gst_add_bus_watch(player);
3958 if (ret != MM_ERROR_NONE) {
3959 LOGE("failed to add bus watch");
3964 return MM_ERROR_NONE;
3967 __mmplayer_gst_destroy_pipeline(player);
3968 return MM_ERROR_PLAYER_INTERNAL;
3972 __mmplayer_reset_gapless_state(mm_player_t* player)
3975 MMPLAYER_RETURN_IF_FAIL(player
3977 && player->pipeline->audiobin
3978 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
3980 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
3987 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
3990 int ret = MM_ERROR_NONE;
3994 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
3996 /* cleanup stuffs */
3997 MMPLAYER_FREEIF(player->type);
3998 player->no_more_pad = FALSE;
3999 player->num_dynamic_pad = 0;
4000 player->demux_pad_index = 0;
4002 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4003 player->subtitle_language_list = NULL;
4004 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4006 __mmplayer_reset_gapless_state(player);
4008 if (player->streamer) {
4009 __mm_player_streaming_deinitialize(player->streamer);
4010 __mm_player_streaming_destroy(player->streamer);
4011 player->streamer = NULL;
4014 /* cleanup unlinked mime type */
4015 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4016 MMPLAYER_FREEIF(player->unlinked_video_mime);
4017 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4019 /* cleanup running stuffs */
4020 __mmplayer_cancel_eos_timer(player);
4022 /* cleanup gst stuffs */
4023 if (player->pipeline) {
4024 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
4025 GstTagList* tag_list = player->pipeline->tag_list;
4027 /* first we need to disconnect all signal hander */
4028 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4031 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4032 MMPlayerGstElement* videobin = player->pipeline->videobin;
4033 MMPlayerGstElement* textbin = player->pipeline->textbin;
4034 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4035 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4036 gst_object_unref(bus);
4038 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4039 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4040 if (ret != MM_ERROR_NONE) {
4041 LOGE("fail to change state to NULL\n");
4042 return MM_ERROR_PLAYER_INTERNAL;
4045 LOGW("succeeded in changing state to NULL\n");
4047 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4050 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4051 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4053 /* free avsysaudiosink
4054 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4055 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4057 MMPLAYER_FREEIF(audiobin);
4058 MMPLAYER_FREEIF(videobin);
4059 MMPLAYER_FREEIF(textbin);
4060 MMPLAYER_FREEIF(mainbin);
4064 gst_tag_list_unref(tag_list);
4066 MMPLAYER_FREEIF(player->pipeline);
4068 MMPLAYER_FREEIF(player->album_art);
4070 if (player->v_stream_caps) {
4071 gst_caps_unref(player->v_stream_caps);
4072 player->v_stream_caps = NULL;
4074 if (player->a_stream_caps) {
4075 gst_caps_unref(player->a_stream_caps);
4076 player->a_stream_caps = NULL;
4079 if (player->s_stream_caps) {
4080 gst_caps_unref(player->s_stream_caps);
4081 player->s_stream_caps = NULL;
4083 __mmplayer_track_destroy(player);
4085 if (player->sink_elements)
4086 g_list_free(player->sink_elements);
4087 player->sink_elements = NULL;
4089 if (player->bufmgr) {
4090 tbm_bufmgr_deinit(player->bufmgr);
4091 player->bufmgr = NULL;
4094 LOGW("finished destroy pipeline\n");
4101 static int __mmplayer_gst_realize(mm_player_t* player)
4104 int ret = MM_ERROR_NONE;
4108 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4110 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4112 ret = __mmplayer_gst_create_pipeline(player);
4114 LOGE("failed to create pipeline\n");
4118 /* set pipeline state to READY */
4119 /* NOTE : state change to READY must be performed sync. */
4120 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4121 ret = __mmplayer_gst_set_state(player,
4122 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4124 if (ret != MM_ERROR_NONE) {
4125 /* return error if failed to set state */
4126 LOGE("failed to set READY state");
4130 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4132 /* create dot before error-return. for debugging */
4133 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4140 static int __mmplayer_gst_unrealize(mm_player_t* player)
4142 int ret = MM_ERROR_NONE;
4146 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4148 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4149 MMPLAYER_PRINT_STATE(player);
4151 /* release miscellaneous information */
4152 __mmplayer_release_misc(player);
4154 /* destroy pipeline */
4155 ret = __mmplayer_gst_destroy_pipeline(player);
4156 if (ret != MM_ERROR_NONE) {
4157 LOGE("failed to destory pipeline\n");
4161 /* release miscellaneous information.
4162 these info needs to be released after pipeline is destroyed. */
4163 __mmplayer_release_misc_post(player);
4165 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4173 __mmplayer_gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
4178 LOGW("set_message_callback is called with invalid player handle\n");
4179 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4182 player->msg_cb = callback;
4183 player->msg_cb_param = user_param;
4185 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
4189 return MM_ERROR_NONE;
4192 int __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
4194 int ret = MM_ERROR_NONE;
4199 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4200 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4201 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4203 memset(data, 0, sizeof(MMPlayerParseProfile));
4205 if (strstr(uri, "es_buff://")) {
4206 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4207 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4208 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4209 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4211 tmp = g_ascii_strdown(uri, strlen(uri));
4212 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4213 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4215 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4217 } else if (strstr(uri, "mms://")) {
4218 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4219 } else if ((path = strstr(uri, "mem://"))) {
4220 ret = __mmplayer_set_mem_uri(data, path, param);
4222 ret = __mmplayer_set_file_uri(data, uri);
4225 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4226 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4227 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4228 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4230 /* dump parse result */
4231 SECURE_LOGW("incoming uri : %s\n", uri);
4232 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
4233 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4241 __mmplayer_can_do_interrupt(mm_player_t *player)
4243 if (!player || !player->pipeline || !player->attrs) {
4244 LOGW("not initialized");
4248 if (player->audio_stream_render_cb) {
4249 LOGW("not support in pcm extraction mode");
4253 /* check if seeking */
4254 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4255 MMMessageParamType msg_param;
4256 memset(&msg_param, 0, sizeof(MMMessageParamType));
4257 msg_param.code = MM_ERROR_PLAYER_SEEK;
4258 player->seek_state = MMPLAYER_SEEK_NONE;
4259 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4263 /* check other thread */
4264 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4265 LOGW("locked already, cmd state : %d", player->cmd);
4267 /* check application command */
4268 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4269 LOGW("playing.. should wait cmd lock then, will be interrupted");
4271 /* lock will be released at mrp_resource_release_cb() */
4272 MMPLAYER_CMD_LOCK(player);
4275 LOGW("nothing to do");
4278 LOGW("can interrupt immediately");
4282 FAILED: /* with CMD UNLOCKED */
4285 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4290 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4293 mm_player_t *player = NULL;
4297 if (user_data == NULL) {
4298 LOGE("- user_data is null\n");
4301 player = (mm_player_t *)user_data;
4303 /* do something to release resource here.
4304 * player stop and interrupt forwarding */
4305 if (!__mmplayer_can_do_interrupt(player)) {
4306 LOGW("no need to interrupt, so leave");
4308 MMMessageParamType msg = {0, };
4311 player->interrupted_by_resource = TRUE;
4313 /* get last play position */
4314 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4315 LOGW("failed to get play position.");
4317 msg.union_type = MM_MSG_UNION_TIME;
4318 msg.time.elapsed = pos;
4319 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4321 LOGD("video resource conflict so, resource will be freed by unrealizing");
4322 if (_mmplayer_unrealize((MMHandleType)player))
4323 LOGW("failed to unrealize");
4325 /* lock is called in __mmplayer_can_do_interrupt() */
4326 MMPLAYER_CMD_UNLOCK(player);
4329 if (res == player->video_overlay_resource)
4330 player->video_overlay_resource = FALSE;
4332 player->video_decoder_resource = FALSE;
4340 __mmplayer_initialize_video_roi(mm_player_t *player)
4342 player->video_roi.scale_x = 0.0;
4343 player->video_roi.scale_y = 0.0;
4344 player->video_roi.scale_width = 1.0;
4345 player->video_roi.scale_height = 1.0;
4349 _mmplayer_create_player(MMHandleType handle)
4351 int ret = MM_ERROR_PLAYER_INTERNAL;
4352 bool enabled = false;
4354 mm_player_t* player = MM_PLAYER_CAST(handle);
4358 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4360 /* initialize player state */
4361 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4362 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4363 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4364 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4366 /* check current state */
4367 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4369 /* construct attributes */
4370 player->attrs = _mmplayer_construct_attribute(handle);
4372 if (!player->attrs) {
4373 LOGE("Failed to construct attributes\n");
4377 /* initialize gstreamer with configured parameter */
4378 if (!__mmplayer_init_gstreamer(player)) {
4379 LOGE("Initializing gstreamer failed\n");
4380 _mmplayer_deconstruct_attribute(handle);
4384 /* create lock. note that g_tread_init() has already called in gst_init() */
4385 g_mutex_init(&player->fsink_lock);
4387 /* create update tag lock */
4388 g_mutex_init(&player->update_tag_lock);
4390 /* create gapless play mutex */
4391 g_mutex_init(&player->gapless_play_thread_mutex);
4393 /* create gapless play cond */
4394 g_cond_init(&player->gapless_play_thread_cond);
4396 /* create gapless play thread */
4397 player->gapless_play_thread =
4398 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4399 if (!player->gapless_play_thread) {
4400 LOGE("failed to create gapless play thread");
4401 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4402 g_mutex_clear(&player->gapless_play_thread_mutex);
4403 g_cond_clear(&player->gapless_play_thread_cond);
4407 player->bus_msg_q = g_queue_new();
4408 if (!player->bus_msg_q) {
4409 LOGE("failed to create queue for bus_msg");
4410 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4414 ret = _mmplayer_initialize_video_capture(player);
4415 if (ret != MM_ERROR_NONE) {
4416 LOGE("failed to initialize video capture\n");
4420 /* initialize resource manager */
4421 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
4422 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
4423 &player->resource_manager)) {
4424 LOGE("failed to initialize resource manager\n");
4425 ret = MM_ERROR_PLAYER_INTERNAL;
4429 /* create video bo lock and cond */
4430 g_mutex_init(&player->video_bo_mutex);
4431 g_cond_init(&player->video_bo_cond);
4433 /* create media stream callback mutex */
4434 g_mutex_init(&player->media_stream_cb_lock);
4436 /* create subtitle info lock and cond */
4437 g_mutex_init(&player->subtitle_info_mutex);
4438 g_cond_init(&player->subtitle_info_cond);
4440 player->streaming_type = STREAMING_SERVICE_NONE;
4442 /* give default value of audio effect setting */
4443 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4444 player->sound.rg_enable = false;
4445 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4447 player->play_subtitle = FALSE;
4448 player->has_closed_caption = FALSE;
4449 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4450 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4451 player->pending_resume = FALSE;
4452 if (player->ini.dump_element_keyword[0][0] == '\0')
4453 player->ini.set_dump_element_flag = FALSE;
4455 player->ini.set_dump_element_flag = TRUE;
4457 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4458 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4459 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4461 /* Set video360 settings to their defaults for just-created player.
4464 player->is_360_feature_enabled = FALSE;
4465 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4466 LOGI("spherical feature info: %d", enabled);
4468 player->is_360_feature_enabled = TRUE;
4470 LOGE("failed to get spherical feature info");
4473 player->is_content_spherical = FALSE;
4474 player->is_video360_enabled = TRUE;
4475 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4476 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4477 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4478 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4479 player->video360_zoom = 1.0f;
4480 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4481 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4483 __mmplayer_initialize_video_roi(player);
4485 /* set player state to null */
4486 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4487 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4489 return MM_ERROR_NONE;
4493 g_mutex_clear(&player->fsink_lock);
4495 /* free update tag lock */
4496 g_mutex_clear(&player->update_tag_lock);
4498 g_queue_free(player->bus_msg_q);
4500 /* free gapless play thread */
4501 if (player->gapless_play_thread) {
4502 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4503 player->gapless_play_thread_exit = TRUE;
4504 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4505 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4507 g_thread_join(player->gapless_play_thread);
4508 player->gapless_play_thread = NULL;
4510 g_mutex_clear(&player->gapless_play_thread_mutex);
4511 g_cond_clear(&player->gapless_play_thread_cond);
4514 /* release attributes */
4515 _mmplayer_deconstruct_attribute(handle);
4523 __mmplayer_init_gstreamer(mm_player_t* player)
4525 static gboolean initialized = FALSE;
4526 static const int max_argc = 50;
4528 gchar** argv = NULL;
4529 gchar** argv2 = NULL;
4535 LOGD("gstreamer already initialized.\n");
4540 argc = malloc(sizeof(int));
4541 argv = malloc(sizeof(gchar*) * max_argc);
4542 argv2 = malloc(sizeof(gchar*) * max_argc);
4544 if (!argc || !argv || !argv2)
4547 memset(argv, 0, sizeof(gchar*) * max_argc);
4548 memset(argv2, 0, sizeof(gchar*) * max_argc);
4552 argv[0] = g_strdup("mmplayer");
4555 for (i = 0; i < 5; i++) {
4556 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4557 if (strlen(player->ini.gst_param[i]) > 0) {
4558 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4563 /* we would not do fork for scanning plugins */
4564 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4567 /* check disable registry scan */
4568 if (player->ini.skip_rescan) {
4569 argv[*argc] = g_strdup("--gst-disable-registry-update");
4573 /* check disable segtrap */
4574 if (player->ini.disable_segtrap) {
4575 argv[*argc] = g_strdup("--gst-disable-segtrap");
4579 LOGD("initializing gstreamer with following parameter\n");
4580 LOGD("argc : %d\n", *argc);
4583 for (i = 0; i < arg_count; i++) {
4585 LOGD("argv[%d] : %s\n", i, argv2[i]);
4588 /* initializing gstreamer */
4589 if (!gst_init_check(argc, &argv, &err)) {
4590 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
4597 for (i = 0; i < arg_count; i++) {
4598 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
4599 MMPLAYER_FREEIF(argv2[i]);
4602 MMPLAYER_FREEIF(argv);
4603 MMPLAYER_FREEIF(argv2);
4604 MMPLAYER_FREEIF(argc);
4614 for (i = 0; i < arg_count; i++) {
4615 LOGD("free[%d] : %s\n", i, argv2[i]);
4616 MMPLAYER_FREEIF(argv2[i]);
4619 MMPLAYER_FREEIF(argv);
4620 MMPLAYER_FREEIF(argv2);
4621 MMPLAYER_FREEIF(argc);
4627 __mmplayer_check_async_state_transition(mm_player_t* player)
4629 GstState element_state = GST_STATE_VOID_PENDING;
4630 GstState element_pending_state = GST_STATE_VOID_PENDING;
4631 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4632 GstElement * element = NULL;
4633 gboolean async = FALSE;
4635 /* check player handle */
4636 MMPLAYER_RETURN_IF_FAIL(player &&
4638 player->pipeline->mainbin &&
4639 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4642 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4644 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4645 LOGD("don't need to check the pipeline state");
4649 MMPLAYER_PRINT_STATE(player);
4651 /* wait for state transition */
4652 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4653 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
4655 if (ret == GST_STATE_CHANGE_FAILURE) {
4656 LOGE(" [%s] state : %s pending : %s \n",
4657 GST_ELEMENT_NAME(element),
4658 gst_element_state_get_name(element_state),
4659 gst_element_state_get_name(element_pending_state));
4661 /* dump state of all element */
4662 __mmplayer_dump_pipeline_state(player);
4667 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
4672 _mmplayer_destroy(MMHandleType handle)
4674 mm_player_t* player = MM_PLAYER_CAST(handle);
4678 /* check player handle */
4679 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4681 /* destroy can called at anytime */
4682 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4684 /* check async state transition */
4685 __mmplayer_check_async_state_transition(player);
4687 /* release gapless play thread */
4688 if (player->gapless_play_thread) {
4689 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4690 player->gapless_play_thread_exit = TRUE;
4691 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4692 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4694 LOGD("waitting for gapless play thread exit\n");
4695 g_thread_join(player->gapless_play_thread);
4696 g_mutex_clear(&player->gapless_play_thread_mutex);
4697 g_cond_clear(&player->gapless_play_thread_cond);
4698 LOGD("gapless play thread released\n");
4701 _mmplayer_release_video_capture(player);
4703 /* de-initialize resource manager */
4704 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4705 player->resource_manager))
4706 LOGE("failed to deinitialize resource manager\n");
4708 /* release pipeline */
4709 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4710 LOGE("failed to destory pipeline\n");
4711 return MM_ERROR_PLAYER_INTERNAL;
4714 g_queue_free(player->bus_msg_q);
4716 /* release subtitle info lock and cond */
4717 g_mutex_clear(&player->subtitle_info_mutex);
4718 g_cond_clear(&player->subtitle_info_cond);
4720 __mmplayer_release_dump_list(player->dump_list);
4722 /* release miscellaneous information */
4723 __mmplayer_release_misc(player);
4725 /* release miscellaneous information.
4726 these info needs to be released after pipeline is destroyed. */
4727 __mmplayer_release_misc_post(player);
4729 /* release attributes */
4730 _mmplayer_deconstruct_attribute(handle);
4733 g_mutex_clear(&player->fsink_lock);
4736 g_mutex_clear(&player->update_tag_lock);
4738 /* release video bo lock and cond */
4739 g_mutex_clear(&player->video_bo_mutex);
4740 g_cond_clear(&player->video_bo_cond);
4742 /* release media stream callback lock */
4743 g_mutex_clear(&player->media_stream_cb_lock);
4747 return MM_ERROR_NONE;
4751 _mmplayer_realize(MMHandleType hplayer)
4753 mm_player_t* player = (mm_player_t*)hplayer;
4756 MMHandleType attrs = 0;
4757 int ret = MM_ERROR_NONE;
4761 /* check player handle */
4762 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4764 /* check current state */
4765 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4767 attrs = MMPLAYER_GET_ATTRS(player);
4769 LOGE("fail to get attributes.\n");
4770 return MM_ERROR_PLAYER_INTERNAL;
4772 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4773 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4775 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4776 ret = __mmplayer_parse_profile((const char*)uri, param, &player->profile);
4778 if (ret != MM_ERROR_NONE) {
4779 LOGE("failed to parse profile");
4784 if (uri && (strstr(uri, "es_buff://"))) {
4785 if (strstr(uri, "es_buff://push_mode"))
4786 player->es_player_push_mode = TRUE;
4788 player->es_player_push_mode = FALSE;
4791 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4792 LOGW("mms protocol is not supported format.\n");
4793 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4796 if (MMPLAYER_IS_STREAMING(player))
4797 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4799 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4801 player->smooth_streaming = FALSE;
4802 player->videodec_linked = 0;
4803 player->audiodec_linked = 0;
4804 player->textsink_linked = 0;
4805 player->is_external_subtitle_present = FALSE;
4806 player->is_external_subtitle_added_now = FALSE;
4807 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4808 player->video360_metadata.is_spherical = -1;
4809 player->is_openal_plugin_used = FALSE;
4810 player->demux_pad_index = 0;
4811 player->subtitle_language_list = NULL;
4812 player->is_subtitle_force_drop = FALSE;
4813 player->last_multiwin_status = FALSE;
4815 __mmplayer_track_initialize(player);
4816 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4818 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4819 player->streamer = __mm_player_streaming_create();
4820 __mm_player_streaming_initialize(player->streamer);
4823 /* realize pipeline */
4824 ret = __mmplayer_gst_realize(player);
4825 if (ret != MM_ERROR_NONE)
4826 LOGE("fail to realize the player.\n");
4828 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4836 _mmplayer_unrealize(MMHandleType hplayer)
4838 mm_player_t* player = (mm_player_t*)hplayer;
4839 int ret = MM_ERROR_NONE;
4843 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4845 MMPLAYER_CMD_UNLOCK(player);
4846 /* destroy the gst bus msg thread which is created during realize.
4847 this funct have to be called before getting cmd lock. */
4848 __mmplayer_bus_msg_thread_destroy(player);
4849 MMPLAYER_CMD_LOCK(player);
4851 /* check current state */
4852 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4854 /* check async state transition */
4855 __mmplayer_check_async_state_transition(player);
4857 /* unrealize pipeline */
4858 ret = __mmplayer_gst_unrealize(player);
4860 /* set asm stop if success */
4861 if (MM_ERROR_NONE == ret) {
4862 if (!player->interrupted_by_resource) {
4863 if (player->video_decoder_resource != NULL) {
4864 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4865 player->video_decoder_resource);
4866 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4867 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
4869 player->video_decoder_resource = NULL;
4872 if (player->video_overlay_resource != NULL) {
4873 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4874 player->video_overlay_resource);
4875 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4876 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
4878 player->video_overlay_resource = NULL;
4881 ret = mm_resource_manager_commit(player->resource_manager);
4882 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4883 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
4886 LOGE("failed and don't change asm state to stop");
4894 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
4896 mm_player_t* player = (mm_player_t*)hplayer;
4898 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4900 return __mmplayer_gst_set_message_callback(player, callback, user_param);
4904 _mmplayer_get_state(MMHandleType hplayer, int* state)
4906 mm_player_t *player = (mm_player_t*)hplayer;
4908 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
4910 *state = MMPLAYER_CURRENT_STATE(player);
4912 return MM_ERROR_NONE;
4917 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
4919 mm_player_t* player = (mm_player_t*) hplayer;
4920 GstElement* vol_element = NULL;
4925 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4927 LOGD("volume [L]=%f:[R]=%f\n",
4928 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
4930 /* invalid factor range or not */
4931 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
4932 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
4933 LOGE("Invalid factor!(valid factor:0~1.0)\n");
4934 return MM_ERROR_INVALID_ARGUMENT;
4938 /* not support to set other value into each channel */
4939 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
4940 return MM_ERROR_INVALID_ARGUMENT;
4942 /* Save volume to handle. Currently the first array element will be saved. */
4943 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
4945 /* check pipeline handle */
4946 if (!player->pipeline || !player->pipeline->audiobin) {
4947 LOGD("audiobin is not created yet\n");
4948 LOGD("but, current stored volume will be set when it's created.\n");
4950 /* NOTE : stored volume will be used in create_audiobin
4951 * returning MM_ERROR_NONE here makes application to able to
4952 * set volume at anytime.
4954 return MM_ERROR_NONE;
4957 /* setting volume to volume element */
4958 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
4961 LOGD("volume is set [%f]\n", player->sound.volume);
4962 g_object_set(vol_element, "volume", player->sound.volume, NULL);
4967 return MM_ERROR_NONE;
4972 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
4974 mm_player_t* player = (mm_player_t*) hplayer;
4979 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4980 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
4982 /* returning stored volume */
4983 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
4984 volume->level[i] = player->sound.volume;
4988 return MM_ERROR_NONE;
4992 _mmplayer_set_mute(MMHandleType hplayer, int mute)
4994 mm_player_t* player = (mm_player_t*) hplayer;
4995 GstElement* vol_element = NULL;
4999 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5001 /* mute value shoud 0 or 1 */
5002 if (mute != 0 && mute != 1) {
5003 LOGE("bad mute value\n");
5005 /* FIXIT : definitly, we need _BAD_PARAM error code */
5006 return MM_ERROR_INVALID_ARGUMENT;
5009 player->sound.mute = mute;
5011 /* just hold mute value if pipeline is not ready */
5012 if (!player->pipeline || !player->pipeline->audiobin) {
5013 LOGD("pipeline is not ready. holding mute value\n");
5014 return MM_ERROR_NONE;
5017 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5019 /* NOTE : volume will only created when the bt is enabled */
5021 LOGD("mute : %d\n", mute);
5022 g_object_set(vol_element, "mute", mute, NULL);
5024 LOGD("volume elemnet is not created. using volume in audiosink\n");
5028 return MM_ERROR_NONE;
5032 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
5034 mm_player_t* player = (mm_player_t*) hplayer;
5038 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5039 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5041 /* just hold mute value if pipeline is not ready */
5042 if (!player->pipeline || !player->pipeline->audiobin) {
5043 LOGD("pipeline is not ready. returning stored value\n");
5044 *pmute = player->sound.mute;
5045 return MM_ERROR_NONE;
5048 *pmute = player->sound.mute;
5052 return MM_ERROR_NONE;
5056 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5058 mm_player_t* player = (mm_player_t*) hplayer;
5062 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5064 player->video_stream_changed_cb = callback;
5065 player->video_stream_changed_cb_user_param = user_param;
5066 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
5070 return MM_ERROR_NONE;
5074 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5076 mm_player_t* player = (mm_player_t*) hplayer;
5080 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5082 player->audio_stream_changed_cb = callback;
5083 player->audio_stream_changed_cb_user_param = user_param;
5084 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
5088 return MM_ERROR_NONE;
5092 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5094 mm_player_t *player = (mm_player_t*) hplayer;
5098 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5100 player->audio_stream_render_cb = callback;
5101 player->audio_stream_cb_user_param = user_param;
5102 player->audio_stream_sink_sync = sync;
5103 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5107 return MM_ERROR_NONE;
5111 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5113 mm_player_t* player = (mm_player_t*) hplayer;
5117 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5119 if (callback && !player->bufmgr)
5120 player->bufmgr = tbm_bufmgr_init(-1);
5122 player->set_mode.media_packet_video_stream = (callback) ? true : false;
5123 player->video_stream_cb = callback;
5124 player->video_stream_cb_user_param = user_param;
5126 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5130 return MM_ERROR_NONE;
5134 _mmplayer_start(MMHandleType hplayer)
5136 mm_player_t* player = (mm_player_t*) hplayer;
5137 gint ret = MM_ERROR_NONE;
5141 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5143 /* check current state */
5144 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5146 /* start pipeline */
5147 ret = __mmplayer_gst_start(player);
5148 if (ret != MM_ERROR_NONE)
5149 LOGE("failed to start player.\n");
5151 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5152 LOGD("force playing start even during buffering");
5153 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5161 /* NOTE: post "not supported codec message" to application
5162 * when one codec is not found during AUTOPLUGGING in MSL.
5163 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5164 * And, if any codec is not found, don't send message here.
5165 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5168 __mmplayer_handle_missed_plugin(mm_player_t* player)
5170 MMMessageParamType msg_param;
5171 memset(&msg_param, 0, sizeof(MMMessageParamType));
5172 gboolean post_msg_direct = FALSE;
5176 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5178 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
5179 player->not_supported_codec, player->can_support_codec);
5181 if (player->not_found_demuxer) {
5182 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5183 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5185 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5186 MMPLAYER_FREEIF(msg_param.data);
5188 return MM_ERROR_NONE;
5191 if (player->not_supported_codec) {
5192 if (player->can_support_codec) {
5193 // There is one codec to play
5194 post_msg_direct = TRUE;
5196 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5197 post_msg_direct = TRUE;
5200 if (post_msg_direct) {
5201 MMMessageParamType msg_param;
5202 memset(&msg_param, 0, sizeof(MMMessageParamType));
5204 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5205 LOGW("not found AUDIO codec, posting error code to application.\n");
5207 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5208 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5209 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5210 LOGW("not found VIDEO codec, posting error code to application.\n");
5212 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5213 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5216 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5218 MMPLAYER_FREEIF(msg_param.data);
5220 return MM_ERROR_NONE;
5222 // no any supported codec case
5223 LOGW("not found any codec, posting error code to application.\n");
5225 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5226 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5227 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5229 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5230 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5233 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5235 MMPLAYER_FREEIF(msg_param.data);
5241 return MM_ERROR_NONE;
5244 static void __mmplayer_check_pipeline(mm_player_t* player)
5246 GstState element_state = GST_STATE_VOID_PENDING;
5247 GstState element_pending_state = GST_STATE_VOID_PENDING;
5249 int ret = MM_ERROR_NONE;
5251 if (player->gapless.reconfigure) {
5252 LOGW("pipeline is under construction.\n");
5254 MMPLAYER_PLAYBACK_LOCK(player);
5255 MMPLAYER_PLAYBACK_UNLOCK(player);
5257 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5259 /* wait for state transition */
5260 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5262 if (ret == GST_STATE_CHANGE_FAILURE)
5263 LOGE("failed to change pipeline state within %d sec\n", timeout);
5267 /* NOTE : it should be able to call 'stop' anytime*/
5269 _mmplayer_stop(MMHandleType hplayer)
5271 mm_player_t* player = (mm_player_t*)hplayer;
5272 int ret = MM_ERROR_NONE;
5276 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5278 /* check current state */
5279 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5281 /* check pipline building state */
5282 __mmplayer_check_pipeline(player);
5283 __mmplayer_reset_gapless_state(player);
5285 /* NOTE : application should not wait for EOS after calling STOP */
5286 __mmplayer_cancel_eos_timer(player);
5289 player->seek_state = MMPLAYER_SEEK_NONE;
5292 ret = __mmplayer_gst_stop(player);
5294 if (ret != MM_ERROR_NONE)
5295 LOGE("failed to stop player.\n");
5303 _mmplayer_pause(MMHandleType hplayer)
5305 mm_player_t* player = (mm_player_t*)hplayer;
5306 gint64 pos_nsec = 0;
5307 gboolean async = FALSE;
5308 gint ret = MM_ERROR_NONE;
5312 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5314 /* check current state */
5315 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5317 /* check pipline building state */
5318 __mmplayer_check_pipeline(player);
5320 switch (MMPLAYER_CURRENT_STATE(player)) {
5321 case MM_PLAYER_STATE_READY:
5323 /* check prepare async or not.
5324 * In the case of streaming playback, it's recommned to avoid blocking wait.
5326 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5327 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5329 /* Changing back sync of rtspsrc to async */
5330 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5331 LOGD("async prepare working mode for rtsp");
5337 case MM_PLAYER_STATE_PLAYING:
5339 /* NOTE : store current point to overcome some bad operation
5340 *(returning zero when getting current position in paused state) of some
5343 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5344 LOGW("getting current position failed in paused\n");
5346 player->last_position = pos_nsec;
5348 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5349 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5350 This causes problem is position calculation during normal pause resume scenarios also.
5351 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5352 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5353 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5354 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5360 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5361 LOGD("doing async pause in case of ms buff src");
5365 /* pause pipeline */
5366 ret = __mmplayer_gst_pause(player, async);
5368 if (ret != MM_ERROR_NONE)
5369 LOGE("failed to pause player. ret : 0x%x\n", ret);
5371 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5372 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5373 LOGE("failed to update display_rotation");
5381 /* in case of streaming, pause could take long time.*/
5383 _mmplayer_abort_pause(MMHandleType hplayer)
5385 mm_player_t* player = (mm_player_t*)hplayer;
5386 int ret = MM_ERROR_NONE;
5390 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5392 player->pipeline->mainbin,
5393 MM_ERROR_PLAYER_NOT_INITIALIZED);
5395 LOGD("set the pipeline state to READY");
5397 /* set state to READY */
5398 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5399 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5400 if (ret != MM_ERROR_NONE) {
5401 LOGE("fail to change state to READY");
5402 return MM_ERROR_PLAYER_INTERNAL;
5405 LOGD("succeeded in changing state to READY");
5411 _mmplayer_resume(MMHandleType hplayer)
5413 mm_player_t* player = (mm_player_t*)hplayer;
5414 int ret = MM_ERROR_NONE;
5415 gboolean async = FALSE;
5419 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5421 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5422 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5423 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5427 /* Changing back sync mode rtspsrc to async */
5428 LOGD("async resume for rtsp case");
5432 /* check current state */
5433 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5435 ret = __mmplayer_gst_resume(player, async);
5436 if (ret != MM_ERROR_NONE)
5437 LOGE("failed to resume player.\n");
5439 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5440 LOGD("force resume even during buffering");
5441 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5450 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5452 mm_player_t* player = (mm_player_t*)hplayer;
5453 gint64 pos_nsec = 0;
5454 int ret = MM_ERROR_NONE;
5456 signed long long start = 0, stop = 0;
5457 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5460 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5461 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5463 /* The sound of video is not supported under 0.0 and over 2.0. */
5464 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5465 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5468 _mmplayer_set_mute(hplayer, mute);
5470 if (player->playback_rate == rate)
5471 return MM_ERROR_NONE;
5473 /* If the position is reached at start potion during fast backward, EOS is posted.
5474 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5476 player->playback_rate = rate;
5478 current_state = MMPLAYER_CURRENT_STATE(player);
5480 if (current_state != MM_PLAYER_STATE_PAUSED)
5481 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5483 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5485 if ((current_state == MM_PLAYER_STATE_PAUSED)
5486 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5487 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5488 pos_nsec = player->last_position;
5493 stop = GST_CLOCK_TIME_NONE;
5495 start = GST_CLOCK_TIME_NONE;
5499 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5500 player->playback_rate,
5502 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5503 GST_SEEK_TYPE_SET, start,
5504 GST_SEEK_TYPE_SET, stop)) {
5505 LOGE("failed to set speed playback\n");
5506 return MM_ERROR_PLAYER_SEEK;
5509 LOGD("succeeded to set speed playback as %0.1f\n", rate);
5513 return MM_ERROR_NONE;;
5517 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5519 mm_player_t* player = (mm_player_t*)hplayer;
5520 int ret = MM_ERROR_NONE;
5524 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5526 /* check pipline building state */
5527 __mmplayer_check_pipeline(player);
5529 ret = __mmplayer_gst_set_position(player, position, FALSE);
5537 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5539 mm_player_t* player = (mm_player_t*)hplayer;
5540 int ret = MM_ERROR_NONE;
5542 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5544 ret = __mmplayer_gst_get_position(player, position);
5550 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5552 mm_player_t* player = (mm_player_t*)hplayer;
5553 int ret = MM_ERROR_NONE;
5555 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5556 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5558 *duration = player->duration;
5563 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5565 mm_player_t *player = (mm_player_t*)hplayer;
5566 int ret = MM_ERROR_NONE;
5568 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5570 ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5576 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5578 mm_player_t* player = (mm_player_t*)hplayer;
5579 int ret = MM_ERROR_NONE;
5583 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5585 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5593 __mmplayer_is_midi_type(gchar* str_caps)
5595 if ((g_strrstr(str_caps, "audio/midi")) ||
5596 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5597 (g_strrstr(str_caps, "application/x-smaf")) ||
5598 (g_strrstr(str_caps, "audio/x-imelody")) ||
5599 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5600 (g_strrstr(str_caps, "audio/xmf")) ||
5601 (g_strrstr(str_caps, "audio/mxmf"))) {
5610 __mmplayer_is_only_mp3_type(gchar *str_caps)
5612 if (g_strrstr(str_caps, "application/x-id3") ||
5613 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5619 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
5621 GstStructure* caps_structure = NULL;
5622 gint samplerate = 0;
5626 MMPLAYER_RETURN_IF_FAIL(player && caps);
5628 caps_structure = gst_caps_get_structure(caps, 0);
5630 /* set stream information */
5631 gst_structure_get_int(caps_structure, "rate", &samplerate);
5632 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5634 gst_structure_get_int(caps_structure, "channels", &channels);
5635 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5637 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
5641 __mmplayer_update_content_type_info(mm_player_t* player)
5644 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5646 if (__mmplayer_is_midi_type(player->type)) {
5647 player->bypass_audio_effect = TRUE;
5648 } else if (g_strrstr(player->type, "application/x-hls")) {
5649 /* If it can't know exact type when it parses uri because of redirection case,
5650 * it will be fixed by typefinder or when doing autoplugging.
5652 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5653 if (player->streamer) {
5654 player->streamer->is_adaptive_streaming = TRUE;
5655 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5656 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
5658 } else if (g_strrstr(player->type, "application/dash+xml")) {
5659 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5660 if (player->streamer) {
5661 player->streamer->is_adaptive_streaming = TRUE;
5662 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5666 LOGD("uri type : %d", player->profile.uri_type);
5671 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5672 GstCaps *caps, gpointer data)
5674 mm_player_t* player = (mm_player_t*)data;
5679 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5681 /* store type string */
5682 MMPLAYER_FREEIF(player->type);
5683 player->type = gst_caps_to_string(caps);
5685 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
5686 player, player->type, probability, gst_caps_get_size(caps));
5689 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5690 (g_strrstr(player->type, "audio/x-raw-int"))) {
5691 LOGE("not support media format\n");
5693 if (player->msg_posted == FALSE) {
5694 MMMessageParamType msg_param;
5695 memset(&msg_param, 0, sizeof(MMMessageParamType));
5697 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5698 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5700 /* don't post more if one was sent already */
5701 player->msg_posted = TRUE;
5706 __mmplayer_update_content_type_info(player);
5708 pad = gst_element_get_static_pad(tf, "src");
5710 LOGE("fail to get typefind src pad.\n");
5714 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5715 gboolean async = FALSE;
5716 LOGE("failed to autoplug %s\n", player->type);
5718 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5720 if (async && player->msg_posted == FALSE)
5721 __mmplayer_handle_missed_plugin(player);
5727 gst_object_unref(GST_OBJECT(pad));
5735 __mmplayer_gst_make_decodebin(mm_player_t* player)
5737 GstElement *decodebin = NULL;
5741 /* create decodebin */
5742 decodebin = gst_element_factory_make("decodebin", NULL);
5745 LOGE("fail to create decodebin\n");
5749 /* raw pad handling signal */
5750 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5751 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5753 /* no-more-pad pad handling signal */
5754 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5755 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5757 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5758 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5760 /* This signal is emitted when a pad for which there is no further possible
5761 decoding is added to the decodebin.*/
5762 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5763 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5765 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5766 before looking for any elements that can handle that stream.*/
5767 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5768 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5770 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5771 before looking for any elements that can handle that stream.*/
5772 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5773 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5775 /* This signal is emitted once decodebin has finished decoding all the data.*/
5776 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5777 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5779 /* This signal is emitted when a element is added to the bin.*/
5780 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5781 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5788 __mmplayer_gst_make_queue2(mm_player_t *player)
5790 GstElement* queue2 = NULL;
5791 gint64 dur_bytes = 0L;
5792 guint max_buffer_size_bytes = 0;
5793 MMPlayerGstElement *mainbin = NULL;
5794 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5797 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5799 mainbin = player->pipeline->mainbin;
5801 queue2 = gst_element_factory_make("queue2", "queue2");
5803 LOGE("failed to create buffering queue element");
5807 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5808 LOGE("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5810 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5812 if (dur_bytes > 0) {
5813 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
5814 type = MUXED_BUFFER_TYPE_FILE;
5816 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5817 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5823 /* NOTE : in case of ts streaming, player cannot get the correct duration info *
5824 * skip the pull mode(file or ring buffering) setting. */
5825 if (!g_strrstr(player->type, "video/mpegts")) {
5826 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
5827 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
5829 __mm_player_streaming_set_queue2(player->streamer,
5832 max_buffer_size_bytes,
5833 player->ini.http_buffering_time,
5835 player->http_file_buffering_path,
5836 (guint64)dur_bytes);
5843 __mmplayer_gst_create_decoder(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
5845 MMPlayerGstElement* mainbin = NULL;
5846 GstElement* decodebin = NULL;
5847 GstElement* queue2 = NULL;
5848 GstPad* sinkpad = NULL;
5849 GstPad* qsrcpad = NULL;
5850 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
5853 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
5855 mainbin = player->pipeline->mainbin;
5857 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
5859 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
5860 LOGW("need to check: muxed buffer is not null");
5863 queue2 = __mmplayer_gst_make_queue2(player);
5865 LOGE("failed to make queue2");
5869 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
5870 LOGE("failed to add buffering queue");
5874 sinkpad = gst_element_get_static_pad(queue2, "sink");
5875 qsrcpad = gst_element_get_static_pad(queue2, "src");
5877 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
5878 LOGE("failed to link [%s:%s]-[%s:%s]",
5879 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5883 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
5884 LOGE("failed to sync queue2 state with parent");
5888 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
5889 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
5893 gst_object_unref(GST_OBJECT(sinkpad));
5897 /* create decodebin */
5898 decodebin = __mmplayer_gst_make_decodebin(player);
5900 LOGE("failed to make decodebin");
5904 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
5905 LOGE("failed to add decodebin\n");
5909 /* to force caps on the decodebin element and avoid reparsing stuff by
5910 * typefind. It also avoids a deadlock in the way typefind activates pads in
5911 * the state change */
5912 g_object_set(decodebin, "sink-caps", caps, NULL);
5914 sinkpad = gst_element_get_static_pad(decodebin, "sink");
5916 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
5917 LOGE("failed to link [%s:%s]-[%s:%s]",
5918 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5922 gst_object_unref(GST_OBJECT(sinkpad));
5925 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
5926 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
5928 /* set decodebin property about buffer in streaming playback. *
5929 * in case of HLS/DASH, it does not need to have big buffer *
5930 * because it is kind of adaptive streaming. */
5931 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
5932 gdouble high_percent = 0.0;
5934 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
5935 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
5937 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
5938 GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
5940 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
5941 "high-percent", (gint)high_percent,
5942 "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
5943 "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
5944 "max-size-buffers", 0, NULL); // disable or automatic
5947 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
5948 LOGE("failed to sync decodebin state with parent\n");
5959 gst_object_unref(GST_OBJECT(sinkpad));
5962 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
5963 * You need to explicitly set elements to the NULL state before
5964 * dropping the final reference, to allow them to clean up.
5966 gst_element_set_state(queue2, GST_STATE_NULL);
5968 /* And, it still has a parent "player".
5969 * You need to let the parent manage the object instead of unreffing the object directly.
5971 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
5972 gst_object_unref(queue2);
5977 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
5978 * You need to explicitly set elements to the NULL state before
5979 * dropping the final reference, to allow them to clean up.
5981 gst_element_set_state(decodebin, GST_STATE_NULL);
5983 /* And, it still has a parent "player".
5984 * You need to let the parent manage the object instead of unreffing the object directly.
5987 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
5988 gst_object_unref(decodebin);
5996 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
6000 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6001 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6003 LOGD("class : %s, mime : %s \n", factory_class, mime);
6005 /* add missing plugin */
6006 /* NOTE : msl should check missing plugin for image mime type.
6007 * Some motion jpeg clips can have playable audio track.
6008 * So, msl have to play audio after displaying popup written video format not supported.
6010 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6011 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6012 LOGD("not found demuxer\n");
6013 player->not_found_demuxer = TRUE;
6014 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6020 if (!g_strrstr(factory_class, "Demuxer")) {
6021 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6022 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
6023 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6025 /* check that clip have multi tracks or not */
6026 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6027 LOGD("video plugin is already linked\n");
6029 LOGW("add VIDEO to missing plugin\n");
6030 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6031 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6033 } else if (g_str_has_prefix(mime, "audio")) {
6034 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6035 LOGD("audio plugin is already linked\n");
6037 LOGW("add AUDIO to missing plugin\n");
6038 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6039 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6047 return MM_ERROR_NONE;
6052 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6054 mm_player_t* player = (mm_player_t*)data;
6058 MMPLAYER_RETURN_IF_FAIL(player);
6060 /* remove fakesink. */
6061 if (!__mmplayer_gst_remove_fakesink(player,
6062 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6063 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6064 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6065 * source element are not same. To overcome this situation, this function will called
6066 * several places and several times. Therefore, this is not an error case.
6071 LOGD("[handle: %p] pipeline has completely constructed", player);
6073 if ((player->ini.async_start) &&
6074 (player->msg_posted == FALSE) &&
6075 (player->cmd >= MMPLAYER_COMMAND_START))
6076 __mmplayer_handle_missed_plugin(player);
6078 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6082 __mmplayer_check_profile(void)
6085 static int profile_tv = -1;
6087 if (__builtin_expect(profile_tv != -1, 1))
6090 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6091 switch (*profileName) {
6106 __mmplayer_get_next_uri(mm_player_t *player)
6108 MMPlayerParseProfile profile;
6110 guint num_of_list = 0;
6113 num_of_list = g_list_length(player->uri_info.uri_list);
6114 uri_idx = player->uri_info.uri_idx;
6116 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6117 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6118 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6120 LOGW("next uri does not exist");
6124 if (__mmplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
6125 LOGE("failed to parse profile");
6129 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6130 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6131 LOGW("uri type is not supported(%d)", profile.uri_type);
6135 LOGD("success to find next uri %d", uri_idx);
6139 if (uri_idx == num_of_list) {
6140 LOGE("failed to find next uri");
6144 player->uri_info.uri_idx = uri_idx;
6145 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6147 if (mm_attrs_commit_all(player->attrs)) {
6148 LOGE("failed to commit");
6152 SECURE_LOGD("next playback uri: %s", uri);
6157 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6159 #define REPEAT_COUNT_INFINITELY -1
6160 #define REPEAT_COUNT_MIN 2
6162 MMHandleType attrs = 0;
6166 guint num_of_list = 0;
6167 int profile_tv = -1;
6171 LOGD("checking for gapless play option");
6173 if (player->pipeline->textbin) {
6174 LOGE("subtitle path is enabled. gapless play is not supported.\n");
6178 attrs = MMPLAYER_GET_ATTRS(player);
6180 LOGE("fail to get attributes.\n");
6184 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6186 /* gapless playback is not supported in case of video at TV profile. */
6187 profile_tv = __mmplayer_check_profile();
6188 if (profile_tv && video) {
6189 LOGW("not support video gapless playback");
6193 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6194 LOGE("failed to get play count");
6196 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6197 LOGE("failed to get gapless mode");
6199 /* check repeat count in case of audio */
6201 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6202 LOGW("gapless is disabled");
6206 num_of_list = g_list_length(player->uri_info.uri_list);
6208 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6210 if (num_of_list == 0) {
6211 /* audio looping path */
6212 if (count >= REPEAT_COUNT_MIN) {
6213 /* decrease play count */
6214 /* we succeeded to rewind. update play count and then wait for next EOS */
6217 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6219 /* commit attribute */
6220 if (mm_attrs_commit_all(attrs))
6221 LOGE("failed to commit attribute");
6222 } else if (count != REPEAT_COUNT_INFINITELY) {
6223 LOGD("there is no next uri and no repeat");
6227 LOGD("looping cnt %d", count);
6229 /* gapless playback path */
6230 if (!__mmplayer_get_next_uri(player)) {
6231 LOGE("failed to get next uri");
6239 LOGE("unable to play gapless path. EOS will be posted soon");
6244 __mmplayer_initialize_gapless_play(mm_player_t *player)
6250 player->smooth_streaming = FALSE;
6251 player->videodec_linked = 0;
6252 player->audiodec_linked = 0;
6253 player->textsink_linked = 0;
6254 player->is_external_subtitle_present = FALSE;
6255 player->is_external_subtitle_added_now = FALSE;
6256 player->not_supported_codec = MISSING_PLUGIN_NONE;
6257 player->can_support_codec = FOUND_PLUGIN_NONE;
6258 player->pending_seek.is_pending = FALSE;
6259 player->pending_seek.pos = 0;
6260 player->msg_posted = FALSE;
6261 player->has_many_types = FALSE;
6262 player->no_more_pad = FALSE;
6263 player->not_found_demuxer = 0;
6264 player->seek_state = MMPLAYER_SEEK_NONE;
6265 player->is_subtitle_force_drop = FALSE;
6266 player->play_subtitle = FALSE;
6267 player->adjust_subtitle_pos = 0;
6269 player->total_bitrate = 0;
6270 player->total_maximum_bitrate = 0;
6272 __mmplayer_track_initialize(player);
6273 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6275 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6276 player->bitrate[i] = 0;
6277 player->maximum_bitrate[i] = 0;
6280 if (player->v_stream_caps) {
6281 gst_caps_unref(player->v_stream_caps);
6282 player->v_stream_caps = NULL;
6285 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6287 /* clean found parsers */
6288 if (player->parsers) {
6289 GList *parsers = player->parsers;
6290 for (; parsers; parsers = g_list_next(parsers)) {
6291 gchar *name = parsers->data;
6292 MMPLAYER_FREEIF(name);
6294 g_list_free(player->parsers);
6295 player->parsers = NULL;
6298 /* clean found audio decoders */
6299 if (player->audio_decoders) {
6300 GList *a_dec = player->audio_decoders;
6301 for (; a_dec; a_dec = g_list_next(a_dec)) {
6302 gchar *name = a_dec->data;
6303 MMPLAYER_FREEIF(name);
6305 g_list_free(player->audio_decoders);
6306 player->audio_decoders = NULL;
6313 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6315 MMPlayerGstElement *mainbin = NULL;
6316 MMMessageParamType msg_param = {0,};
6317 GstElement *element = NULL;
6318 MMHandleType attrs = 0;
6320 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6324 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6325 LOGE("player is not initialized");
6329 mainbin = player->pipeline->mainbin;
6330 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6332 attrs = MMPLAYER_GET_ATTRS(player);
6334 LOGE("fail to get attributes");
6338 /* Initialize Player values */
6339 __mmplayer_initialize_gapless_play(player);
6341 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6343 if (__mmplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6344 LOGE("failed to parse profile");
6345 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6349 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6350 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6351 LOGE("dash or hls is not supportable");
6352 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6356 element = __mmplayer_gst_create_source(player);
6358 LOGE("no source element was created");
6362 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6363 LOGE("failed to add source element to pipeline");
6364 gst_object_unref(GST_OBJECT(element));
6369 /* take source element */
6370 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6371 mainbin[MMPLAYER_M_SRC].gst = element;
6375 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6376 if (player->streamer == NULL) {
6377 player->streamer = __mm_player_streaming_create();
6378 __mm_player_streaming_initialize(player->streamer);
6381 elem_idx = MMPLAYER_M_TYPEFIND;
6382 element = gst_element_factory_make("typefind", "typefinder");
6383 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6384 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6386 elem_idx = MMPLAYER_M_AUTOPLUG;
6387 element = __mmplayer_gst_make_decodebin(player);
6390 /* check autoplug element is OK */
6392 LOGE("can not create element(%d)", elem_idx);
6396 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6397 LOGE("failed to add sinkbin to pipeline");
6398 gst_object_unref(GST_OBJECT(element));
6403 mainbin[elem_idx].id = elem_idx;
6404 mainbin[elem_idx].gst = element;
6406 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6407 LOGE("Failed to link src - autoplug(or typefind)");
6411 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6412 LOGE("Failed to change state of src element");
6416 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6417 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6418 LOGE("Failed to change state of decodebin");
6422 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6423 LOGE("Failed to change state of src element");
6428 player->gapless.stream_changed = TRUE;
6429 player->gapless.running = TRUE;
6435 MMPLAYER_PLAYBACK_UNLOCK(player);
6437 if (!player->msg_posted) {
6438 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6439 player->msg_posted = TRUE;
6446 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6448 mm_player_selector_t *selector = &player->selector[type];
6449 MMPlayerGstElement *sinkbin = NULL;
6450 enum MainElementID selectorId = MMPLAYER_M_NUM;
6451 enum MainElementID sinkId = MMPLAYER_M_NUM;
6452 GstPad *srcpad = NULL;
6453 GstPad *sinkpad = NULL;
6454 gboolean send_notice = FALSE;
6457 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6459 LOGD("type %d", type);
6462 case MM_PLAYER_TRACK_TYPE_AUDIO:
6463 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6464 sinkId = MMPLAYER_A_BIN;
6465 sinkbin = player->pipeline->audiobin;
6467 case MM_PLAYER_TRACK_TYPE_VIDEO:
6468 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6469 sinkId = MMPLAYER_V_BIN;
6470 sinkbin = player->pipeline->videobin;
6473 case MM_PLAYER_TRACK_TYPE_TEXT:
6474 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6475 sinkId = MMPLAYER_T_BIN;
6476 sinkbin = player->pipeline->textbin;
6479 LOGE("requested type is not supportable");
6484 if (player->pipeline->mainbin[selectorId].gst) {
6487 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6489 if (selector->event_probe_id != 0)
6490 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6491 selector->event_probe_id = 0;
6493 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6494 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6496 if (srcpad && sinkpad) {
6497 /* after getting drained signal there is no data flows, so no need to do pad_block */
6498 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6499 gst_pad_unlink(srcpad, sinkpad);
6501 /* send custom event to sink pad to handle it at video sink */
6503 LOGD("send custom event to sinkpad");
6504 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6505 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6506 gst_pad_send_event(sinkpad, event);
6510 gst_object_unref(sinkpad);
6513 gst_object_unref(srcpad);
6516 LOGD("selector release");
6518 /* release and unref requests pad from the selector */
6519 for (n = 0; n < selector->channels->len; n++) {
6520 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6521 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6523 g_ptr_array_set_size(selector->channels, 0);
6525 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6526 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6528 player->pipeline->mainbin[selectorId].gst = NULL;
6536 __mmplayer_deactivate_old_path(mm_player_t *player)
6539 MMPLAYER_RETURN_IF_FAIL(player);
6541 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6542 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6543 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6544 LOGE("deactivate selector error");
6548 __mmplayer_track_destroy(player);
6549 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6551 if (player->streamer) {
6552 __mm_player_streaming_deinitialize(player->streamer);
6553 __mm_player_streaming_destroy(player->streamer);
6554 player->streamer = NULL;
6557 MMPLAYER_PLAYBACK_LOCK(player);
6558 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6565 if (!player->msg_posted) {
6566 MMMessageParamType msg = {0,};
6569 msg.code = MM_ERROR_PLAYER_INTERNAL;
6570 LOGE("gapless_uri_play> deactivate error");
6572 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6573 player->msg_posted = TRUE;
6578 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
6580 int result = MM_ERROR_NONE;
6581 mm_player_t* player = (mm_player_t*) hplayer;
6584 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6587 player->http_file_buffering_path = (gchar*)file_path;
6588 LOGD("temp file path: %s\n", player->http_file_buffering_path);
6594 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
6596 int result = MM_ERROR_NONE;
6597 mm_player_t* player = (mm_player_t*) hplayer;
6600 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6602 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6603 if (mm_attrs_commit_all(player->attrs)) {
6604 LOGE("failed to commit the original uri.\n");
6605 result = MM_ERROR_PLAYER_INTERNAL;
6607 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6608 LOGE("failed to add the original uri in the uri list.\n");
6615 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
6617 mm_player_t* player = (mm_player_t*) hplayer;
6618 guint num_of_list = 0;
6622 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6623 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6625 if (player->pipeline && player->pipeline->textbin) {
6626 LOGE("subtitle path is enabled.\n");
6627 return MM_ERROR_PLAYER_INVALID_STATE;
6630 num_of_list = g_list_length(player->uri_info.uri_list);
6632 if (is_first_path == TRUE) {
6633 if (num_of_list == 0) {
6634 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6635 LOGD("add original path : %s", uri);
6637 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6638 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6640 LOGD("change original path : %s", uri);
6643 MMHandleType attrs = 0;
6644 attrs = MMPLAYER_GET_ATTRS(player);
6646 if (num_of_list == 0) {
6647 char *original_uri = NULL;
6650 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6652 if (!original_uri) {
6653 LOGE("there is no original uri.");
6654 return MM_ERROR_PLAYER_INVALID_STATE;
6657 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6658 player->uri_info.uri_idx = 0;
6660 LOGD("add original path at first : %s", original_uri);
6664 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6665 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6669 return MM_ERROR_NONE;
6672 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
6674 mm_player_t* player = (mm_player_t*) hplayer;
6675 char *next_uri = NULL;
6676 guint num_of_list = 0;
6679 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6681 num_of_list = g_list_length(player->uri_info.uri_list);
6683 if (num_of_list > 0) {
6684 gint uri_idx = player->uri_info.uri_idx;
6686 if (uri_idx < num_of_list-1)
6691 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6692 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
6694 *uri = g_strdup(next_uri);
6698 return MM_ERROR_NONE;
6702 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
6703 GstCaps *caps, gpointer data)
6705 mm_player_t* player = (mm_player_t*)data;
6706 const gchar* klass = NULL;
6707 const gchar* mime = NULL;
6708 gchar* caps_str = NULL;
6710 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6711 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6712 caps_str = gst_caps_to_string(caps);
6714 LOGW("unknown type of caps : %s from %s",
6715 caps_str, GST_ELEMENT_NAME(elem));
6717 MMPLAYER_FREEIF(caps_str);
6719 /* There is no available codec. */
6720 __mmplayer_check_not_supported_codec(player, klass, mime);
6724 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
6725 GstCaps * caps, gpointer data)
6727 mm_player_t* player = (mm_player_t*)data;
6728 const char* mime = NULL;
6729 gboolean ret = TRUE;
6731 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6732 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6734 if (g_str_has_prefix(mime, "audio")) {
6735 GstStructure* caps_structure = NULL;
6736 gint samplerate = 0;
6738 gchar *caps_str = NULL;
6740 caps_structure = gst_caps_get_structure(caps, 0);
6741 gst_structure_get_int(caps_structure, "rate", &samplerate);
6742 gst_structure_get_int(caps_structure, "channels", &channels);
6744 if ((channels > 0 && samplerate == 0)) {
6745 LOGD("exclude audio...");
6749 caps_str = gst_caps_to_string(caps);
6750 /* set it directly because not sent by TAG */
6751 if (g_strrstr(caps_str, "mobile-xmf"))
6752 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6753 MMPLAYER_FREEIF(caps_str);
6754 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6755 MMMessageParamType msg_param;
6756 memset(&msg_param, 0, sizeof(MMMessageParamType));
6757 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6758 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6759 LOGD("video file is not supported on this device");
6761 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6762 LOGD("already video linked");
6765 LOGD("found new stream");
6772 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
6774 int ret = MM_ERROR_NONE;
6776 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6778 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6779 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6781 LOGD("audio codec type: %d", codec_type);
6782 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6783 /* sw codec will be skipped */
6784 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6785 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6786 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6787 ret = MM_ERROR_PLAYER_INTERNAL;
6791 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6792 /* hw codec will be skipped */
6793 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6794 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6795 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6796 ret = MM_ERROR_PLAYER_INTERNAL;
6801 /* set stream information */
6802 if (!player->audiodec_linked)
6803 __mmplayer_set_audio_attrs(player, caps);
6805 /* update codec info */
6806 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6807 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6808 player->audiodec_linked = 1;
6810 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6812 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6814 LOGD("video codec type: %d", codec_type);
6815 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6816 /* sw codec is skipped */
6817 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
6818 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
6819 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
6820 ret = MM_ERROR_PLAYER_INTERNAL;
6824 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6825 /* hw codec is skipped */
6826 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
6827 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
6828 ret = MM_ERROR_PLAYER_INTERNAL;
6833 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
6834 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
6836 /* mark video decoder for acquire */
6837 if (player->video_decoder_resource == NULL) {
6838 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
6839 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
6840 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
6841 &player->video_decoder_resource)
6842 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6843 LOGE("could not mark video_decoder resource for acquire");
6844 ret = MM_ERROR_PLAYER_INTERNAL;
6848 LOGW("video decoder resource is already acquired, skip it.");
6849 ret = MM_ERROR_PLAYER_INTERNAL;
6853 player->interrupted_by_resource = FALSE;
6854 /* acquire resources for video playing */
6855 if (mm_resource_manager_commit(player->resource_manager)
6856 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6857 LOGE("could not acquire resources for video decoding\n");
6858 ret = MM_ERROR_PLAYER_INTERNAL;
6863 /* update codec info */
6864 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
6865 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
6866 player->videodec_linked = 1;
6874 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
6875 GstCaps* caps, GstElementFactory* factory, gpointer data)
6877 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
6878 We are defining our own and will be removed when it actually exposed */
6880 GST_AUTOPLUG_SELECT_TRY,
6881 GST_AUTOPLUG_SELECT_EXPOSE,
6882 GST_AUTOPLUG_SELECT_SKIP
6883 } GstAutoplugSelectResult;
6885 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
6886 mm_player_t* player = (mm_player_t*)data;
6888 gchar* factory_name = NULL;
6889 gchar* caps_str = NULL;
6890 const gchar* klass = NULL;
6893 factory_name = GST_OBJECT_NAME(factory);
6894 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
6895 caps_str = gst_caps_to_string(caps);
6897 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
6899 /* store type string */
6900 if (player->type == NULL) {
6901 player->type = gst_caps_to_string(caps);
6902 __mmplayer_update_content_type_info(player);
6905 /* filtering exclude keyword */
6906 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
6907 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
6908 LOGW("skipping [%s] by exculde keyword [%s]",
6909 factory_name, player->ini.exclude_element_keyword[idx]);
6911 result = GST_AUTOPLUG_SELECT_SKIP;
6916 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
6917 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
6918 LOGW("skipping [%s] by unsupported codec keyword [%s]",
6919 factory_name, player->ini.unsupported_codec_keyword[idx]);
6920 result = GST_AUTOPLUG_SELECT_SKIP;
6925 /* exclude webm format */
6926 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
6927 * because webm format is not supportable.
6928 * If webm is disabled in "autoplug-continue", there is no state change
6929 * failure or error because the decodebin will expose the pad directly.
6930 * It make MSL invoke _prepare_async_callback.
6931 * So, we need to disable webm format in "autoplug-select" */
6932 if (caps_str && strstr(caps_str, "webm")) {
6933 LOGW("webm is not supported");
6934 result = GST_AUTOPLUG_SELECT_SKIP;
6938 /* check factory class for filtering */
6939 /* NOTE : msl don't need to use image plugins.
6940 * So, those plugins should be skipped for error handling.
6942 if (g_strrstr(klass, "Codec/Decoder/Image")) {
6943 LOGD("skipping [%s] by not required\n", factory_name);
6944 result = GST_AUTOPLUG_SELECT_SKIP;
6948 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
6949 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
6950 // TO CHECK : subtitle if needed, add subparse exception.
6951 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
6952 result = GST_AUTOPLUG_SELECT_SKIP;
6956 if (g_strrstr(factory_name, "mpegpsdemux")) {
6957 LOGD("skipping PS container - not support\n");
6958 result = GST_AUTOPLUG_SELECT_SKIP;
6962 if (g_strrstr(factory_name, "mssdemux"))
6963 player->smooth_streaming = TRUE;
6965 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
6966 (g_strrstr(klass, "Codec/Decoder/Video"))) {
6969 GstStructure *str = NULL;
6970 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
6972 /* don't make video because of not required */
6973 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
6974 (!player->set_mode.media_packet_video_stream)) {
6975 LOGD("no need video decoding, expose pad");
6976 result = GST_AUTOPLUG_SELECT_EXPOSE;
6980 /* get w/h for omx state-tune */
6981 /* FIXME: deprecated? */
6982 str = gst_caps_get_structure(caps, 0);
6983 gst_structure_get_int(str, "width", &width);
6986 if (player->v_stream_caps) {
6987 gst_caps_unref(player->v_stream_caps);
6988 player->v_stream_caps = NULL;
6991 player->v_stream_caps = gst_caps_copy(caps);
6992 LOGD("take caps for video state tune");
6993 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
6997 if (g_strrstr(klass, "Codec/Decoder")) {
6998 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
6999 LOGD("skipping %s codec", factory_name);
7000 result = GST_AUTOPLUG_SELECT_SKIP;
7006 MMPLAYER_FREEIF(caps_str);
7012 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
7015 //mm_player_t* player = (mm_player_t*)data;
7016 GstCaps* caps = NULL;
7018 LOGD("[Decodebin2] pad-removed signal\n");
7020 caps = gst_pad_query_caps(new_pad, NULL);
7022 gchar* caps_str = NULL;
7023 caps_str = gst_caps_to_string(caps);
7025 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7027 MMPLAYER_FREEIF(caps_str);
7028 gst_caps_unref(caps);
7033 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7035 mm_player_t* player = (mm_player_t*)data;
7036 GstIterator *iter = NULL;
7037 GValue item = { 0, };
7039 gboolean done = FALSE;
7040 gboolean is_all_drained = TRUE;
7043 MMPLAYER_RETURN_IF_FAIL(player);
7045 LOGD("__mmplayer_gst_decode_drained");
7047 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7048 LOGW("Fail to get cmd lock");
7052 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7053 !__mmplayer_verify_gapless_play_path(player)) {
7054 LOGD("decoding is finished.");
7055 __mmplayer_reset_gapless_state(player);
7056 MMPLAYER_CMD_UNLOCK(player);
7060 player->gapless.reconfigure = TRUE;
7062 /* check decodebin src pads whether they received EOS or not */
7063 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7066 switch (gst_iterator_next(iter, &item)) {
7067 case GST_ITERATOR_OK:
7068 pad = g_value_get_object(&item);
7069 if (pad && !GST_PAD_IS_EOS(pad)) {
7070 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7071 is_all_drained = FALSE;
7074 g_value_reset(&item);
7076 case GST_ITERATOR_RESYNC:
7077 gst_iterator_resync(iter);
7079 case GST_ITERATOR_ERROR:
7080 case GST_ITERATOR_DONE:
7085 g_value_unset(&item);
7086 gst_iterator_free(iter);
7088 if (!is_all_drained) {
7089 LOGD("Wait util the all pads get EOS.");
7090 MMPLAYER_CMD_UNLOCK(player);
7095 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7096 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7098 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7099 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7100 __mmplayer_deactivate_old_path(player);
7101 MMPLAYER_CMD_UNLOCK(player);
7107 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7109 mm_player_t* player = (mm_player_t*)data;
7110 const gchar* klass = NULL;
7111 gchar* factory_name = NULL;
7113 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7114 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7116 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
7118 if (__mmplayer_add_dump_buffer_probe(player, element))
7119 LOGD("add buffer probe");
7122 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7123 gchar* selected = NULL;
7124 selected = g_strdup(GST_ELEMENT_NAME(element));
7125 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7129 if (g_strrstr(klass, "Parser")) {
7130 gchar* selected = NULL;
7132 selected = g_strdup(factory_name);
7133 player->parsers = g_list_append(player->parsers, selected);
7136 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7137 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7138 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7140 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7141 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7143 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7144 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7145 "max-video-width", player->adaptive_info.limit.width,
7146 "max-video-height", player->adaptive_info.limit.height, NULL);
7148 } else if (g_strrstr(klass, "Demuxer")) {
7149 //LOGD("plugged element is demuxer. take it");
7150 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7151 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7154 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7155 int surface_type = 0;
7157 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7160 // to support trust-zone only
7161 if (g_strrstr(factory_name, "asfdemux")) {
7162 LOGD("set file-location %s\n", player->profile.uri);
7163 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7164 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7165 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
7166 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7167 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7168 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7169 (__mmplayer_is_only_mp3_type(player->type))) {
7170 LOGD("[mpegaudioparse] set streaming pull mode.");
7171 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7173 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7174 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7177 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7178 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7179 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7181 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7182 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7184 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7185 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7186 (MMPLAYER_IS_DASH_STREAMING(player))) {
7187 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7188 __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time);
7189 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7198 __mmplayer_release_misc(mm_player_t* player)
7201 bool cur_mode = player->set_mode.rich_audio;
7204 MMPLAYER_RETURN_IF_FAIL(player);
7206 player->video_stream_cb = NULL;
7207 player->video_stream_cb_user_param = NULL;
7208 player->video_stream_prerolled = FALSE;
7210 player->audio_stream_render_cb = NULL;
7211 player->audio_stream_cb_user_param = NULL;
7212 player->audio_stream_sink_sync = false;
7214 player->video_stream_changed_cb = NULL;
7215 player->video_stream_changed_cb_user_param = NULL;
7217 player->audio_stream_changed_cb = NULL;
7218 player->audio_stream_changed_cb_user_param = NULL;
7220 player->sent_bos = FALSE;
7221 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7223 player->seek_state = MMPLAYER_SEEK_NONE;
7225 player->total_bitrate = 0;
7226 player->total_maximum_bitrate = 0;
7228 player->not_found_demuxer = 0;
7230 player->last_position = 0;
7231 player->duration = 0;
7232 player->http_content_size = 0;
7233 player->not_supported_codec = MISSING_PLUGIN_NONE;
7234 player->can_support_codec = FOUND_PLUGIN_NONE;
7235 player->pending_seek.is_pending = FALSE;
7236 player->pending_seek.pos = 0;
7237 player->msg_posted = FALSE;
7238 player->has_many_types = FALSE;
7239 player->is_subtitle_force_drop = FALSE;
7240 player->play_subtitle = FALSE;
7241 player->adjust_subtitle_pos = 0;
7242 player->last_multiwin_status = FALSE;
7243 player->has_closed_caption = FALSE;
7244 player->set_mode.media_packet_video_stream = false;
7245 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7246 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7248 player->set_mode.rich_audio = cur_mode;
7250 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7251 player->bitrate[i] = 0;
7252 player->maximum_bitrate[i] = 0;
7255 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7257 /* remove media stream cb(appsrc cb) */
7258 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7259 player->media_stream_buffer_status_cb[i] = NULL;
7260 player->media_stream_seek_data_cb[i] = NULL;
7261 player->buffer_cb_user_param[i] = NULL;
7262 player->seek_cb_user_param[i] = NULL;
7264 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7266 /* free memory related to audio effect */
7267 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7269 if (player->adaptive_info.var_list) {
7270 g_list_free_full(player->adaptive_info.var_list, g_free);
7271 player->adaptive_info.var_list = NULL;
7274 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7275 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7276 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7278 /* Reset video360 settings to their defaults in case if the pipeline is to be
7281 player->video360_metadata.is_spherical = -1;
7282 player->is_openal_plugin_used = FALSE;
7284 player->is_content_spherical = FALSE;
7285 player->is_video360_enabled = TRUE;
7286 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7287 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7288 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7289 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7290 player->video360_zoom = 1.0f;
7291 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7292 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7294 player->sound.rg_enable = false;
7296 __mmplayer_initialize_video_roi(player);
7301 __mmplayer_release_misc_post(mm_player_t* player)
7303 char *original_uri = NULL;
7306 /* player->pipeline is already released before. */
7308 MMPLAYER_RETURN_IF_FAIL(player);
7310 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7312 /* clean found parsers */
7313 if (player->parsers) {
7314 GList *parsers = player->parsers;
7315 for (; parsers; parsers = g_list_next(parsers)) {
7316 gchar *name = parsers->data;
7317 MMPLAYER_FREEIF(name);
7319 g_list_free(player->parsers);
7320 player->parsers = NULL;
7323 /* clean found audio decoders */
7324 if (player->audio_decoders) {
7325 GList *a_dec = player->audio_decoders;
7326 for (; a_dec; a_dec = g_list_next(a_dec)) {
7327 gchar *name = a_dec->data;
7328 MMPLAYER_FREEIF(name);
7330 g_list_free(player->audio_decoders);
7331 player->audio_decoders = NULL;
7334 /* clean the uri list except original uri */
7335 if (player->uri_info.uri_list) {
7336 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7338 if (player->attrs) {
7339 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7340 LOGD("restore original uri = %s\n", original_uri);
7342 if (mm_attrs_commit_all(player->attrs))
7343 LOGE("failed to commit the original uri.\n");
7346 GList *uri_list = player->uri_info.uri_list;
7347 for (; uri_list; uri_list = g_list_next(uri_list)) {
7348 gchar *uri = uri_list->data;
7349 MMPLAYER_FREEIF(uri);
7351 g_list_free(player->uri_info.uri_list);
7352 player->uri_info.uri_list = NULL;
7355 /* clear the audio stream buffer list */
7356 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7358 /* clear the video stream bo list */
7359 __mmplayer_video_stream_destroy_bo_list(player);
7360 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7362 if (player->profile.input_mem.buf) {
7363 free(player->profile.input_mem.buf);
7364 player->profile.input_mem.buf = NULL;
7366 player->profile.input_mem.len = 0;
7367 player->profile.input_mem.offset = 0;
7369 player->uri_info.uri_idx = 0;
7374 __mmplayer_check_subtitle(mm_player_t* player)
7376 MMHandleType attrs = 0;
7377 char *subtitle_uri = NULL;
7381 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7383 /* get subtitle attribute */
7384 attrs = MMPLAYER_GET_ATTRS(player);
7388 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7389 if (!subtitle_uri || !strlen(subtitle_uri))
7392 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7393 player->is_external_subtitle_present = TRUE;
7401 __mmplayer_cancel_eos_timer(mm_player_t* player)
7403 MMPLAYER_RETURN_IF_FAIL(player);
7405 if (player->eos_timer) {
7406 LOGD("cancel eos timer");
7407 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7408 player->eos_timer = 0;
7415 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
7419 MMPLAYER_RETURN_IF_FAIL(player);
7420 MMPLAYER_RETURN_IF_FAIL(sink);
7422 player->sink_elements =
7423 g_list_append(player->sink_elements, sink);
7429 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
7433 MMPLAYER_RETURN_IF_FAIL(player);
7434 MMPLAYER_RETURN_IF_FAIL(sink);
7436 player->sink_elements =
7437 g_list_remove(player->sink_elements, sink);
7443 __mmplayer_add_signal_connection(mm_player_t* player, GObject* object,
7444 MMPlayerSignalType type, const gchar* signal, GCallback cb_funct, gpointer u_data)
7446 MMPlayerSignalItem* item = NULL;
7449 MMPLAYER_RETURN_IF_FAIL(player);
7451 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7452 LOGE("invalid signal type [%d]", type);
7456 item = (MMPlayerSignalItem*)g_malloc(sizeof(MMPlayerSignalItem));
7458 LOGE("cannot connect signal [%s]", signal);
7463 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7464 player->signals[type] = g_list_append(player->signals[type], item);
7470 /* NOTE : be careful with calling this api. please refer to below glib comment
7471 * glib comment : Note that there is a bug in GObject that makes this function much
7472 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7473 * will no longer be called, but, the signal handler is not currently disconnected.
7474 * If the instance is itself being freed at the same time than this doesn't matter,
7475 * since the signal will automatically be removed, but if instance persists,
7476 * then the signal handler will leak. You should not remove the signal yourself
7477 * because in a future versions of GObject, the handler will automatically be
7480 * It's possible to work around this problem in a way that will continue to work
7481 * with future versions of GObject by checking that the signal handler is still
7482 * connected before disconnected it:
7484 * if (g_signal_handler_is_connected(instance, id))
7485 * g_signal_handler_disconnect(instance, id);
7488 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
7490 GList* sig_list = NULL;
7491 MMPlayerSignalItem* item = NULL;
7495 MMPLAYER_RETURN_IF_FAIL(player);
7497 LOGD("release signals type : %d", type);
7499 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7500 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7501 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7502 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7503 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7504 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7508 sig_list = player->signals[type];
7510 for (; sig_list; sig_list = sig_list->next) {
7511 item = sig_list->data;
7513 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7514 if (g_signal_handler_is_connected(item->obj, item->sig))
7515 g_signal_handler_disconnect(item->obj, item->sig);
7518 MMPLAYER_FREEIF(item);
7521 g_list_free(player->signals[type]);
7522 player->signals[type] = NULL;
7529 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7531 mm_player_t* player = 0;
7532 int prev_display_surface_type = 0;
7533 void *prev_display_overlay = NULL;
7537 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7538 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7540 player = MM_PLAYER_CAST(handle);
7542 /* check video sinkbin is created */
7543 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7544 LOGE("Videosink is already created");
7545 return MM_ERROR_NONE;
7548 LOGD("videosink element is not yet ready");
7550 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7551 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7553 return MM_ERROR_INVALID_ARGUMENT;
7556 /* load previous attributes */
7557 if (player->attrs) {
7558 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7559 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7560 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7561 if (prev_display_surface_type == surface_type) {
7562 LOGD("incoming display surface type is same as previous one, do nothing..");
7564 return MM_ERROR_NONE;
7567 LOGE("failed to load attributes");
7569 return MM_ERROR_PLAYER_INTERNAL;
7572 /* videobin is not created yet, so we just set attributes related to display surface */
7573 LOGD("store display attribute for given surface type(%d)", surface_type);
7574 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7575 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7576 if (mm_attrs_commit_all(player->attrs)) {
7577 LOGE("failed to commit attribute");
7579 return MM_ERROR_PLAYER_INTERNAL;
7583 return MM_ERROR_NONE;
7586 /* Note : if silent is true, then subtitle would not be displayed. :*/
7587 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7589 mm_player_t* player = (mm_player_t*) hplayer;
7593 /* check player handle */
7594 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7596 player->set_mode.subtitle_off = silent;
7598 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
7602 return MM_ERROR_NONE;
7605 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
7607 MMPlayerGstElement* mainbin = NULL;
7608 MMPlayerGstElement* textbin = NULL;
7609 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7610 GstState current_state = GST_STATE_VOID_PENDING;
7611 GstState element_state = GST_STATE_VOID_PENDING;
7612 GstState element_pending_state = GST_STATE_VOID_PENDING;
7614 GstEvent *event = NULL;
7615 int result = MM_ERROR_NONE;
7617 GstClock *curr_clock = NULL;
7618 GstClockTime base_time, start_time, curr_time;
7623 /* check player handle */
7624 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7626 player->pipeline->mainbin &&
7627 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7629 mainbin = player->pipeline->mainbin;
7630 textbin = player->pipeline->textbin;
7632 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7634 // sync clock with current pipeline
7635 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7636 curr_time = gst_clock_get_time(curr_clock);
7638 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7639 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7641 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7642 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7644 if (current_state > GST_STATE_READY) {
7645 // sync state with current pipeline
7646 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7647 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7648 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7650 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7651 if (GST_STATE_CHANGE_FAILURE == ret) {
7652 LOGE("fail to state change.\n");
7653 result = MM_ERROR_PLAYER_INTERNAL;
7657 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7658 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7661 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7662 gst_object_unref(curr_clock);
7665 // seek to current position
7666 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7667 result = MM_ERROR_PLAYER_INVALID_STATE;
7668 LOGE("gst_element_query_position failed, invalid state\n");
7672 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7673 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);
7675 __mmplayer_gst_send_event_to_sink(player, event);
7677 result = MM_ERROR_PLAYER_INTERNAL;
7678 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7682 /* sync state with current pipeline */
7683 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7684 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7685 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7687 return MM_ERROR_NONE;
7690 /* release text pipeline resource */
7691 player->textsink_linked = 0;
7693 /* release signal */
7694 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7696 /* release textbin with it's childs */
7697 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7698 MMPLAYER_FREEIF(player->pipeline->textbin);
7699 player->pipeline->textbin = NULL;
7701 /* release subtitle elem */
7702 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7703 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7709 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
7711 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7712 GstState current_state = GST_STATE_VOID_PENDING;
7714 MMHandleType attrs = 0;
7715 MMPlayerGstElement* mainbin = NULL;
7716 MMPlayerGstElement* textbin = NULL;
7718 gchar* subtitle_uri = NULL;
7719 int result = MM_ERROR_NONE;
7720 const gchar *charset = NULL;
7724 /* check player handle */
7725 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7727 player->pipeline->mainbin &&
7728 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7729 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7731 mainbin = player->pipeline->mainbin;
7732 textbin = player->pipeline->textbin;
7734 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7735 if (current_state < GST_STATE_READY) {
7736 result = MM_ERROR_PLAYER_INVALID_STATE;
7737 LOGE("Pipeline is not in proper state\n");
7741 attrs = MMPLAYER_GET_ATTRS(player);
7743 LOGE("cannot get content attribute\n");
7744 result = MM_ERROR_PLAYER_INTERNAL;
7748 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7749 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7750 LOGE("subtitle uri is not proper filepath\n");
7751 result = MM_ERROR_PLAYER_INVALID_URI;
7755 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7756 LOGE("failed to get storage info of subtitle path");
7757 result = MM_ERROR_PLAYER_INVALID_URI;
7761 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
7762 LOGD("new subtitle file path is [%s]\n", filepath);
7764 if (!strcmp(filepath, subtitle_uri)) {
7765 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
7768 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7769 if (mm_attrs_commit_all(player->attrs)) {
7770 LOGE("failed to commit.\n");
7775 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7776 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7777 player->subtitle_language_list = NULL;
7778 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7780 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7781 if (ret != GST_STATE_CHANGE_SUCCESS) {
7782 LOGE("failed to change state of textbin to READY");
7783 result = MM_ERROR_PLAYER_INTERNAL;
7787 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7788 if (ret != GST_STATE_CHANGE_SUCCESS) {
7789 LOGE("failed to change state of subparse to READY");
7790 result = MM_ERROR_PLAYER_INTERNAL;
7794 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7795 if (ret != GST_STATE_CHANGE_SUCCESS) {
7796 LOGE("failed to change state of filesrc to READY");
7797 result = MM_ERROR_PLAYER_INTERNAL;
7801 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7803 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7805 charset = util_get_charset(filepath);
7807 LOGD("detected charset is %s\n", charset);
7808 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7811 result = _mmplayer_sync_subtitle_pipeline(player);
7818 /* API to switch between external subtitles */
7819 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
7821 int result = MM_ERROR_NONE;
7822 mm_player_t* player = (mm_player_t*)hplayer;
7827 /* check player handle */
7828 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7830 /* filepath can be null in idle state */
7832 /* check file path */
7833 if ((path = strstr(filepath, "file://")))
7834 result = util_exist_file_path(path + 7);
7836 result = util_exist_file_path(filepath);
7838 if (result != MM_ERROR_NONE) {
7839 LOGE("invalid subtitle path 0x%X", result);
7840 return result; /* file not found or permission denied */
7844 if (!player->pipeline) {
7846 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7847 if (mm_attrs_commit_all(player->attrs)) {
7848 LOGE("failed to commit"); /* subtitle path will not be created */
7849 return MM_ERROR_PLAYER_INTERNAL;
7852 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7853 /* check filepath */
7854 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7856 if (!__mmplayer_check_subtitle(player)) {
7857 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7858 if (mm_attrs_commit_all(player->attrs)) {
7859 LOGE("failed to commit");
7860 return MM_ERROR_PLAYER_INTERNAL;
7863 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
7864 LOGE("fail to create text pipeline");
7865 return MM_ERROR_PLAYER_INTERNAL;
7868 result = _mmplayer_sync_subtitle_pipeline(player);
7870 result = __mmplayer_change_external_subtitle_language(player, filepath);
7873 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
7874 player->is_external_subtitle_added_now = TRUE;
7876 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7877 if (!player->subtitle_language_list) {
7878 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
7879 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
7880 LOGW("subtitle language list is not updated yet");
7882 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7890 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
7892 int result = MM_ERROR_NONE;
7893 gchar* change_pad_name = NULL;
7894 GstPad* sinkpad = NULL;
7895 MMPlayerGstElement* mainbin = NULL;
7896 enum MainElementID elem_idx = MMPLAYER_M_NUM;
7897 GstCaps* caps = NULL;
7898 gint total_track_num = 0;
7902 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
7903 MM_ERROR_PLAYER_NOT_INITIALIZED);
7905 LOGD("Change Track(%d) to %d\n", type, index);
7907 mainbin = player->pipeline->mainbin;
7909 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
7910 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
7911 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
7912 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
7914 /* Changing Video Track is not supported. */
7915 LOGE("Track Type Error\n");
7919 if (mainbin[elem_idx].gst == NULL) {
7920 result = MM_ERROR_PLAYER_NO_OP;
7921 LOGD("Req track doesn't exist\n");
7925 total_track_num = player->selector[type].total_track_num;
7926 if (total_track_num <= 0) {
7927 result = MM_ERROR_PLAYER_NO_OP;
7928 LOGD("Language list is not available \n");
7932 if ((index < 0) || (index >= total_track_num)) {
7933 result = MM_ERROR_INVALID_ARGUMENT;
7934 LOGD("Not a proper index : %d \n", index);
7938 /*To get the new pad from the selector*/
7939 change_pad_name = g_strdup_printf("sink_%u", index);
7940 if (change_pad_name == NULL) {
7941 result = MM_ERROR_PLAYER_INTERNAL;
7942 LOGD("Pad does not exists\n");
7946 LOGD("new active pad name: %s\n", change_pad_name);
7948 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
7949 if (sinkpad == NULL) {
7950 LOGD("sinkpad is NULL");
7951 result = MM_ERROR_PLAYER_INTERNAL;
7955 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
7956 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
7958 caps = gst_pad_get_current_caps(sinkpad);
7959 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
7962 gst_object_unref(sinkpad);
7964 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
7965 __mmplayer_set_audio_attrs(player, caps);
7969 MMPLAYER_FREEIF(change_pad_name);
7973 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
7975 int result = MM_ERROR_NONE;
7976 mm_player_t* player = NULL;
7977 MMPlayerGstElement* mainbin = NULL;
7979 gint current_active_index = 0;
7981 GstState current_state = GST_STATE_VOID_PENDING;
7982 GstEvent* event = NULL;
7987 player = (mm_player_t*)hplayer;
7988 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7990 if (!player->pipeline) {
7991 LOGE("Track %d pre setting -> %d\n", type, index);
7993 player->selector[type].active_pad_index = index;
7997 mainbin = player->pipeline->mainbin;
7999 current_active_index = player->selector[type].active_pad_index;
8001 /*If index is same as running index no need to change the pad*/
8002 if (current_active_index == index)
8005 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8006 result = MM_ERROR_PLAYER_INVALID_STATE;
8010 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8011 if (current_state < GST_STATE_PAUSED) {
8012 result = MM_ERROR_PLAYER_INVALID_STATE;
8013 LOGW("Pipeline not in porper state\n");
8017 result = __mmplayer_change_selector_pad(player, type, index);
8018 if (result != MM_ERROR_NONE) {
8019 LOGE("change selector pad error\n");
8023 player->selector[type].active_pad_index = index;
8025 if (current_state == GST_STATE_PLAYING) {
8026 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);
8028 __mmplayer_gst_send_event_to_sink(player, event);
8030 result = MM_ERROR_PLAYER_INTERNAL;
8039 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
8041 mm_player_t* player = (mm_player_t*) hplayer;
8045 /* check player handle */
8046 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8048 *silent = player->set_mode.subtitle_off;
8050 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
8054 return MM_ERROR_NONE;
8058 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8060 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8061 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8063 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8064 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8068 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8069 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8070 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8071 mm_player_dump_t *dump_s;
8072 dump_s = g_malloc(sizeof(mm_player_dump_t));
8074 if (dump_s == NULL) {
8075 LOGE("malloc fail");
8079 dump_s->dump_element_file = NULL;
8080 dump_s->dump_pad = NULL;
8081 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8083 if (dump_s->dump_pad) {
8084 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
8085 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]);
8086 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8087 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);
8088 /* add list for removed buffer probe and close FILE */
8089 player->dump_list = g_list_append(player->dump_list, dump_s);
8090 LOGD("%s sink pad added buffer probe for dump", factory_name);
8095 LOGE("failed to get %s sink pad added", factory_name);
8102 static GstPadProbeReturn
8103 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8105 FILE *dump_data = (FILE *) u_data;
8107 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8108 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8110 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
8112 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8114 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8116 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8118 return GST_PAD_PROBE_OK;
8122 __mmplayer_release_dump_list(GList *dump_list)
8125 GList *d_list = dump_list;
8126 for (; d_list; d_list = g_list_next(d_list)) {
8127 mm_player_dump_t *dump_s = d_list->data;
8128 if (dump_s->dump_pad) {
8129 if (dump_s->probe_handle_id)
8130 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8132 if (dump_s->dump_element_file) {
8133 fclose(dump_s->dump_element_file);
8134 dump_s->dump_element_file = NULL;
8136 MMPLAYER_FREEIF(dump_s);
8138 g_list_free(dump_list);
8144 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
8146 mm_player_t* player = (mm_player_t*) hplayer;
8150 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8151 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8153 *exist = player->has_closed_caption;
8157 return MM_ERROR_NONE;
8160 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
8164 // LOGD("unref internal gst buffer %p", buffer);
8165 gst_buffer_unref((GstBuffer *)buffer);
8171 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8173 mm_player_t *player = (mm_player_t *) hplayer;
8177 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8178 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8180 if (MMPLAYER_IS_STREAMING(player))
8181 *timeout = player->ini.live_state_change_timeout;
8183 *timeout = player->ini.localplayback_state_change_timeout;
8185 LOGD("timeout = %d", *timeout);
8188 return MM_ERROR_NONE;
8191 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8193 mm_player_t* player = (mm_player_t*) hplayer;
8197 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8198 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8200 *num = player->video_num_buffers;
8201 *extra_num = player->video_extra_num_buffers;
8203 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8206 return MM_ERROR_NONE;
8210 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
8214 MMPLAYER_RETURN_IF_FAIL(player);
8216 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8218 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8219 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8220 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8221 player->storage_info[i].id = -1;
8222 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8224 if (path_type != MMPLAYER_PATH_MAX)
8232 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8234 int ret = MM_ERROR_NONE;
8235 mm_player_t* player = (mm_player_t*)hplayer;
8236 MMMessageParamType msg_param = {0, };
8239 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8241 LOGW("state changed storage %d:%d", id, state);
8243 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8244 return MM_ERROR_NONE;
8246 /* FIXME: text path should be handled seperately. */
8247 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8248 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8249 LOGW("external storage is removed");
8251 if (player->msg_posted == FALSE) {
8252 memset(&msg_param, 0, sizeof(MMMessageParamType));
8253 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8254 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8255 player->msg_posted = TRUE;
8258 /* unrealize the player */
8259 ret = _mmplayer_unrealize(hplayer);
8260 if (ret != MM_ERROR_NONE)
8261 LOGE("failed to unrealize");
8268 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8270 int ret = MM_ERROR_NONE;
8271 mm_player_t* player = (mm_player_t*) hplayer;
8272 int idx = 0, total = 0;
8273 gchar *result = NULL, *tmp = NULL;
8276 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8277 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8279 total = *num = g_list_length(player->adaptive_info.var_list);
8281 LOGW("There is no stream variant info.");
8285 result = g_strdup("");
8286 for (idx = 0 ; idx < total ; idx++) {
8287 VariantData *v_data = NULL;
8288 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8291 gchar data[64] = {0};
8292 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8294 tmp = g_strconcat(result, data, NULL);
8298 LOGW("There is no variant data in %d", idx);
8303 *var_info = (char *)result;
8305 LOGD("variant info %d:%s", *num, *var_info);
8310 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8312 int ret = MM_ERROR_NONE;
8313 mm_player_t* player = (mm_player_t*) hplayer;
8316 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8318 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8320 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8321 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8322 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8324 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8325 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8326 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8327 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8329 /* FIXME: seek to current position for applying new variant limitation */
8337 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8339 int ret = MM_ERROR_NONE;
8340 mm_player_t* player = (mm_player_t*) hplayer;
8343 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8344 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8346 *bandwidth = player->adaptive_info.limit.bandwidth;
8347 *width = player->adaptive_info.limit.width;
8348 *height = player->adaptive_info.limit.height;
8350 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8356 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
8358 int ret = MM_ERROR_NONE;
8359 mm_player_t* player = (mm_player_t*) hplayer;
8362 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8364 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
8365 LOGW("buffer_ms will not be applied.");
8367 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
8369 if (player->streamer == NULL) {
8370 player->streamer = __mm_player_streaming_create();
8371 __mm_player_streaming_initialize(player->streamer);
8375 player->streamer->buffering_req.prebuffer_time = buffer_ms;
8377 if (rebuffer_ms >= 0)
8378 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
8385 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
8387 int ret = MM_ERROR_NONE;
8388 mm_player_t* player = (mm_player_t*) hplayer;
8391 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8392 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8394 if (player->streamer == NULL) {
8395 player->streamer = __mm_player_streaming_create();
8396 __mm_player_streaming_initialize(player->streamer);
8399 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
8400 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8402 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
8408 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8410 #define IDX_FIRST_SW_CODEC 0
8411 mm_player_t* player = (mm_player_t*) hplayer;
8412 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8413 MMHandleType attrs = 0;
8416 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8418 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8419 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8420 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8422 switch (stream_type) {
8423 case MM_PLAYER_STREAM_TYPE_AUDIO:
8424 /* to support audio codec selection, codec info have to be added in ini file as below.
8425 audio codec element hw = xxxx
8426 audio codec element sw = avdec */
8427 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8428 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8429 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8430 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8431 LOGE("There is no audio codec info for codec_type %d", codec_type);
8432 return MM_ERROR_PLAYER_NO_OP;
8435 case MM_PLAYER_STREAM_TYPE_VIDEO:
8436 /* to support video codec selection, codec info have to be added in ini file as below.
8437 video codec element hw = omx
8438 video codec element sw = avdec */
8439 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8440 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8441 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8442 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8443 LOGE("There is no video codec info for codec_type %d", codec_type);
8444 return MM_ERROR_PLAYER_NO_OP;
8448 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8449 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8453 LOGD("update %s codec_type to %d", attr_name, codec_type);
8455 attrs = MMPLAYER_GET_ATTRS(player);
8456 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8458 if (mm_attrs_commit_all(player->attrs)) {
8459 LOGE("failed to commit codec_type attributes");
8460 return MM_ERROR_PLAYER_INTERNAL;
8464 return MM_ERROR_NONE;
8468 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8470 mm_player_t* player = (mm_player_t*) hplayer;
8471 GstElement* rg_vol_element = NULL;
8475 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8477 player->sound.rg_enable = enabled;
8479 /* just hold rgvolume enable value if pipeline is not ready */
8480 if (!player->pipeline || !player->pipeline->audiobin) {
8481 LOGD("pipeline is not ready. holding rgvolume enable value\n");
8482 return MM_ERROR_NONE;
8485 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8487 if (!rg_vol_element) {
8488 LOGD("rgvolume element is not created");
8489 return MM_ERROR_PLAYER_INTERNAL;
8493 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8495 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8499 return MM_ERROR_NONE;
8503 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8505 mm_player_t* player = (mm_player_t*) hplayer;
8506 GstElement* rg_vol_element = NULL;
8507 gboolean enable = FALSE;
8511 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8512 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8514 /* just hold enable_rg value if pipeline is not ready */
8515 if (!player->pipeline || !player->pipeline->audiobin) {
8516 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
8517 *enabled = player->sound.rg_enable;
8518 return MM_ERROR_NONE;
8521 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8523 if (!rg_vol_element) {
8524 LOGD("rgvolume element is not created");
8525 return MM_ERROR_PLAYER_INTERNAL;
8528 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8533 return MM_ERROR_NONE;
8537 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8539 mm_player_t* player = (mm_player_t*) hplayer;
8540 MMHandleType attrs = 0;
8541 void *handle = NULL;
8542 int ret = MM_ERROR_NONE;
8546 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8548 attrs = MMPLAYER_GET_ATTRS(player);
8549 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8551 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8553 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8554 return MM_ERROR_PLAYER_INTERNAL;
8557 player->video_roi.scale_x = scale_x;
8558 player->video_roi.scale_y = scale_y;
8559 player->video_roi.scale_width = scale_width;
8560 player->video_roi.scale_height = scale_height;
8562 /* check video sinkbin is created */
8563 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8564 return MM_ERROR_NONE;
8566 if (!gst_video_overlay_set_video_roi_area(
8567 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8568 scale_x, scale_y, scale_width, scale_height))
8569 ret = MM_ERROR_PLAYER_INTERNAL;
8571 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8572 scale_x, scale_y, scale_width, scale_height);
8580 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8582 mm_player_t* player = (mm_player_t*) hplayer;
8583 int ret = MM_ERROR_NONE;
8587 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8588 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8590 *scale_x = player->video_roi.scale_x;
8591 *scale_y = player->video_roi.scale_y;
8592 *scale_width = player->video_roi.scale_width;
8593 *scale_height = player->video_roi.scale_height;
8595 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8596 *scale_x, *scale_y, *scale_width, *scale_height);
8602 __mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs)
8604 gboolean ret = FALSE;
8605 gint64 dur_nsec = 0;
8606 LOGD("try to update duration");
8608 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8609 player->duration = dur_nsec;
8610 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8614 if (player->duration < 0) {
8615 LOGW("duration is Non-Initialized !!!");
8616 player->duration = 0;
8619 /* update streaming service type */
8620 player->streaming_type = __mmplayer_get_stream_service_type(player);
8622 /* check duration is OK */
8623 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
8624 /* FIXIT : find another way to get duration here. */
8625 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8632 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8634 /* update audio params
8635 NOTE : We need original audio params and it can be only obtained from src pad of audio
8636 decoder. Below code only valid when we are not using 'resampler' just before
8637 'audioconverter'. */
8638 GstCaps *caps_a = NULL;
8640 gint samplerate = 0, channels = 0;
8641 GstStructure* p = NULL;
8643 LOGD("try to update audio attrs");
8645 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8646 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8648 pad = gst_element_get_static_pad(
8649 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8652 LOGW("failed to get pad from audiosink");
8656 caps_a = gst_pad_get_current_caps(pad);
8659 LOGW("not ready to get audio caps");
8660 gst_object_unref(pad);
8664 p = gst_caps_get_structure(caps_a, 0);
8666 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8668 gst_structure_get_int(p, "rate", &samplerate);
8669 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8671 gst_structure_get_int(p, "channels", &channels);
8672 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8674 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8676 gst_caps_unref(caps_a);
8677 gst_object_unref(pad);
8683 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8685 LOGD("try to update video attrs");
8687 GstCaps *caps_v = NULL;
8691 GstStructure* p = NULL;
8693 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8694 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8696 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8698 LOGD("no videosink sink pad");
8702 caps_v = gst_pad_get_current_caps(pad);
8703 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8704 if (!caps_v && player->v_stream_caps) {
8705 caps_v = player->v_stream_caps;
8706 gst_caps_ref(caps_v);
8710 LOGD("no negitiated caps from videosink");
8711 gst_object_unref(pad);
8715 p = gst_caps_get_structure(caps_v, 0);
8716 gst_structure_get_int(p, "width", &width);
8717 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8719 gst_structure_get_int(p, "height", &height);
8720 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8722 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8724 SECURE_LOGD("width : %d height : %d", width, height);
8726 gst_caps_unref(caps_v);
8727 gst_object_unref(pad);
8730 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8731 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8738 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8740 gboolean ret = FALSE;
8741 guint64 data_size = 0;
8745 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8746 if (!player->duration)
8749 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8750 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8751 if (stat(path, &sb) == 0)
8752 data_size = (guint64)sb.st_size;
8754 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8755 data_size = player->http_content_size;
8758 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8761 guint64 bitrate = 0;
8762 guint64 msec_dur = 0;
8764 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8766 bitrate = data_size * 8 * 1000 / msec_dur;
8767 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8768 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8772 LOGD("player duration is less than 0");
8776 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8777 if (player->total_bitrate) {
8778 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
8786 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile* data, const char *uri, int uri_type)
8788 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8789 data->uri_type = uri_type;
8792 __mmplayer_set_mem_uri(MMPlayerParseProfile* data, char *path, void *param)
8794 int ret = MM_ERROR_PLAYER_INVALID_URI;
8796 char *buffer = NULL;
8797 char *seperator = strchr(path, ',');
8798 char ext[100] = {0,}, size[100] = {0,};
8801 if ((buffer = strstr(path, "ext="))) {
8802 buffer += strlen("ext=");
8804 if (strlen(buffer)) {
8805 strncpy(ext, buffer, 99);
8807 if ((seperator = strchr(ext, ','))
8808 || (seperator = strchr(ext, ' '))
8809 || (seperator = strchr(ext, '\0'))) {
8810 seperator[0] = '\0';
8815 if ((buffer = strstr(path, "size="))) {
8816 buffer += strlen("size=");
8818 if (strlen(buffer) > 0) {
8819 strncpy(size, buffer, 99);
8821 if ((seperator = strchr(size, ','))
8822 || (seperator = strchr(size, ' '))
8823 || (seperator = strchr(size, '\0'))) {
8824 seperator[0] = '\0';
8827 mem_size = atoi(size);
8832 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8834 if (mem_size && param) {
8835 if (data->input_mem.buf)
8836 free(data->input_mem.buf);
8837 data->input_mem.buf = malloc(mem_size);
8839 if (data->input_mem.buf) {
8840 memcpy(data->input_mem.buf, param, mem_size);
8841 data->input_mem.len = mem_size;
8842 ret = MM_ERROR_NONE;
8844 LOGE("failed to alloc mem %d", mem_size);
8845 ret = MM_ERROR_PLAYER_INTERNAL;
8848 data->input_mem.offset = 0;
8849 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8856 __mmplayer_set_file_uri(MMPlayerParseProfile* data, const char *uri)
8858 gchar *location = NULL;
8861 int ret = MM_ERROR_NONE;
8863 if ((path = strstr(uri, "file://"))) {
8864 location = g_filename_from_uri(uri, NULL, &err);
8865 if (!location || (err != NULL)) {
8866 LOGE("Invalid URI '%s' for filesrc: %s", path,
8867 (err != NULL) ? err->message : "unknown error");
8873 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8874 return MM_ERROR_PLAYER_INVALID_URI;
8876 LOGD("path from uri: %s", location);
8879 path = (location != NULL) ? (location) : ((char *)uri);
8882 ret = util_exist_file_path(path);
8884 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8885 if (ret == MM_ERROR_NONE) {
8886 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8887 if (util_is_sdp_file(path)) {
8888 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8889 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8891 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8893 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8894 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8896 LOGE("invalid uri, could not play..\n");
8897 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8906 static MMPlayerVideoStreamDataType*
8907 __mmplayer_create_stream_from_pad(GstPad *pad)
8909 GstCaps *caps = NULL;
8910 GstStructure *structure = NULL;
8911 unsigned int fourcc = 0;
8912 const gchar *string_format = NULL;
8913 MMPlayerVideoStreamDataType *stream = NULL;
8915 MMPixelFormatType format;
8917 caps = gst_pad_get_current_caps(pad);
8919 LOGE("Caps is NULL.");
8923 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
8924 structure = gst_caps_get_structure(caps, 0);
8925 gst_structure_get_int(structure, "width", &width);
8926 gst_structure_get_int(structure, "height", &height);
8927 string_format = gst_structure_get_string(structure, "format");
8929 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
8930 format = util_get_pixtype(fourcc);
8931 gst_caps_unref(caps);
8934 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
8935 LOGE("Wrong condition!!");
8939 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
8941 LOGE("failed to alloc mem for video data");
8945 stream->width = width;
8946 stream->height = height;
8947 stream->format = format;
8953 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
8955 unsigned int pitch = 0;
8957 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
8959 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
8960 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
8961 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
8962 stream->stride[index] = pitch;
8963 stream->elevation[index] = stream->height;
8968 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
8970 if (stream->format == MM_PIXEL_FORMAT_I420) {
8971 int ret = TBM_SURFACE_ERROR_NONE;
8972 tbm_surface_h surface;
8973 tbm_surface_info_s info;
8975 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
8977 ret = tbm_surface_get_info(surface, &info);
8978 if (ret != TBM_SURFACE_ERROR_NONE) {
8979 tbm_surface_destroy(surface);
8983 tbm_surface_destroy(surface);
8984 stream->stride[0] = info.planes[0].stride;
8985 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
8986 stream->stride[1] = info.planes[1].stride;
8987 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
8988 stream->stride[2] = info.planes[2].stride;
8989 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
8990 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
8991 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
8992 stream->stride[0] = stream->width * 4;
8993 stream->elevation[0] = stream->height;
8994 stream->bo_size = stream->stride[0] * stream->height;
8996 LOGE("Not support format %d", stream->format);
9004 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9006 tbm_bo_handle thandle;
9008 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9009 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9010 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9014 unsigned char *src = NULL;
9015 unsigned char *dest = NULL;
9016 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9018 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9020 LOGE("fail to gst_memory_map");
9024 if (!mapinfo.data) {
9025 LOGE("data pointer is wrong");
9029 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9030 if (!stream->bo[0]) {
9031 LOGE("Fail to tbm_bo_alloc!!");
9035 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9037 LOGE("thandle pointer is wrong");
9041 if (stream->format == MM_PIXEL_FORMAT_I420) {
9042 src_stride[0] = GST_ROUND_UP_4(stream->width);
9043 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9044 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9045 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9048 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9049 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9051 for (i = 0; i < 3; i++) {
9052 src = mapinfo.data + src_offset[i];
9053 dest = thandle.ptr + dest_offset[i];
9058 for (j = 0; j < stream->height >> k; j++) {
9059 memcpy(dest, src, stream->width>>k);
9060 src += src_stride[i];
9061 dest += stream->stride[i];
9064 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9065 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9067 LOGE("Not support format %d", stream->format);
9071 tbm_bo_unmap(stream->bo[0]);
9072 gst_memory_unmap(mem, &mapinfo);
9078 tbm_bo_unmap(stream->bo[0]);
9081 gst_memory_unmap(mem, &mapinfo);
9087 __mmplayer_set_pause_state(mm_player_t *player)
9089 if (player->sent_bos)
9092 /* rtsp case, get content attrs by GstMessage */
9093 if (MMPLAYER_IS_RTSP_STREAMING(player))
9096 /* it's first time to update all content attrs. */
9097 __mmplayer_update_content_attrs(player, ATTR_ALL);
9101 __mmplayer_set_playing_state(mm_player_t *player)
9103 gchar *audio_codec = NULL;
9105 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9106 /* initialize because auto resume is done well. */
9107 player->resumed_by_rewind = FALSE;
9108 player->playback_rate = 1.0;
9111 if (player->sent_bos)
9114 /* try to get content metadata */
9116 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9117 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9118 * legacy mmfw-player api
9120 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9122 if ((player->cmd == MMPLAYER_COMMAND_START)
9123 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9124 __mmplayer_handle_missed_plugin(player);
9127 /* check audio codec field is set or not
9128 * we can get it from typefinder or codec's caps.
9130 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9132 /* The codec format can't be sent for audio only case like amr, mid etc.
9133 * Because, parser don't make related TAG.
9134 * So, if it's not set yet, fill it with found data.
9137 if (g_strrstr(player->type, "audio/midi"))
9138 audio_codec = "MIDI";
9139 else if (g_strrstr(player->type, "audio/x-amr"))
9140 audio_codec = "AMR";
9141 else if (g_strrstr(player->type, "audio/mpeg")
9142 && !g_strrstr(player->type, "mpegversion= (int)1"))
9143 audio_codec = "AAC";
9145 audio_codec = "unknown";
9147 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9149 if (mm_attrs_commit_all(player->attrs))
9150 LOGE("failed to update attributes\n");
9152 LOGD("set audio codec type with caps\n");