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_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4422 __resource_release_cb, player, &player->resource_manager)
4423 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4424 LOGE("failed to initialize resource manager");
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);
4491 return MM_ERROR_NONE;
4495 g_mutex_clear(&player->fsink_lock);
4497 /* free update tag lock */
4498 g_mutex_clear(&player->update_tag_lock);
4500 g_queue_free(player->bus_msg_q);
4502 /* free gapless play thread */
4503 if (player->gapless_play_thread) {
4504 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4505 player->gapless_play_thread_exit = TRUE;
4506 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4507 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4509 g_thread_join(player->gapless_play_thread);
4510 player->gapless_play_thread = NULL;
4512 g_mutex_clear(&player->gapless_play_thread_mutex);
4513 g_cond_clear(&player->gapless_play_thread_cond);
4516 /* release attributes */
4517 _mmplayer_deconstruct_attribute(handle);
4525 __mmplayer_init_gstreamer(mm_player_t* player)
4527 static gboolean initialized = FALSE;
4528 static const int max_argc = 50;
4530 gchar** argv = NULL;
4531 gchar** argv2 = NULL;
4537 LOGD("gstreamer already initialized.\n");
4542 argc = malloc(sizeof(int));
4543 argv = malloc(sizeof(gchar*) * max_argc);
4544 argv2 = malloc(sizeof(gchar*) * max_argc);
4546 if (!argc || !argv || !argv2)
4549 memset(argv, 0, sizeof(gchar*) * max_argc);
4550 memset(argv2, 0, sizeof(gchar*) * max_argc);
4554 argv[0] = g_strdup("mmplayer");
4557 for (i = 0; i < 5; i++) {
4558 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4559 if (strlen(player->ini.gst_param[i]) > 0) {
4560 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4565 /* we would not do fork for scanning plugins */
4566 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4569 /* check disable registry scan */
4570 if (player->ini.skip_rescan) {
4571 argv[*argc] = g_strdup("--gst-disable-registry-update");
4575 /* check disable segtrap */
4576 if (player->ini.disable_segtrap) {
4577 argv[*argc] = g_strdup("--gst-disable-segtrap");
4581 LOGD("initializing gstreamer with following parameter\n");
4582 LOGD("argc : %d\n", *argc);
4585 for (i = 0; i < arg_count; i++) {
4587 LOGD("argv[%d] : %s\n", i, argv2[i]);
4590 /* initializing gstreamer */
4591 if (!gst_init_check(argc, &argv, &err)) {
4592 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
4599 for (i = 0; i < arg_count; i++) {
4600 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
4601 MMPLAYER_FREEIF(argv2[i]);
4604 MMPLAYER_FREEIF(argv);
4605 MMPLAYER_FREEIF(argv2);
4606 MMPLAYER_FREEIF(argc);
4616 for (i = 0; i < arg_count; i++) {
4617 LOGD("free[%d] : %s\n", i, argv2[i]);
4618 MMPLAYER_FREEIF(argv2[i]);
4621 MMPLAYER_FREEIF(argv);
4622 MMPLAYER_FREEIF(argv2);
4623 MMPLAYER_FREEIF(argc);
4629 __mmplayer_check_async_state_transition(mm_player_t* player)
4631 GstState element_state = GST_STATE_VOID_PENDING;
4632 GstState element_pending_state = GST_STATE_VOID_PENDING;
4633 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4634 GstElement * element = NULL;
4635 gboolean async = FALSE;
4637 /* check player handle */
4638 MMPLAYER_RETURN_IF_FAIL(player &&
4640 player->pipeline->mainbin &&
4641 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4644 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4646 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4647 LOGD("don't need to check the pipeline state");
4651 MMPLAYER_PRINT_STATE(player);
4653 /* wait for state transition */
4654 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4655 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
4657 if (ret == GST_STATE_CHANGE_FAILURE) {
4658 LOGE(" [%s] state : %s pending : %s \n",
4659 GST_ELEMENT_NAME(element),
4660 gst_element_state_get_name(element_state),
4661 gst_element_state_get_name(element_pending_state));
4663 /* dump state of all element */
4664 __mmplayer_dump_pipeline_state(player);
4669 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
4674 _mmplayer_destroy(MMHandleType handle)
4676 mm_player_t* player = MM_PLAYER_CAST(handle);
4680 /* check player handle */
4681 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4683 /* destroy can called at anytime */
4684 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4686 /* check async state transition */
4687 __mmplayer_check_async_state_transition(player);
4689 /* release gapless play thread */
4690 if (player->gapless_play_thread) {
4691 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4692 player->gapless_play_thread_exit = TRUE;
4693 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4694 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4696 LOGD("waitting for gapless play thread exit\n");
4697 g_thread_join(player->gapless_play_thread);
4698 g_mutex_clear(&player->gapless_play_thread_mutex);
4699 g_cond_clear(&player->gapless_play_thread_cond);
4700 LOGD("gapless play thread released\n");
4703 _mmplayer_release_video_capture(player);
4705 /* de-initialize resource manager */
4706 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4707 player->resource_manager))
4708 LOGE("failed to deinitialize resource manager\n");
4710 /* release pipeline */
4711 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4712 LOGE("failed to destory pipeline\n");
4713 return MM_ERROR_PLAYER_INTERNAL;
4716 g_queue_free(player->bus_msg_q);
4718 /* release subtitle info lock and cond */
4719 g_mutex_clear(&player->subtitle_info_mutex);
4720 g_cond_clear(&player->subtitle_info_cond);
4722 __mmplayer_release_dump_list(player->dump_list);
4724 /* release miscellaneous information */
4725 __mmplayer_release_misc(player);
4727 /* release miscellaneous information.
4728 these info needs to be released after pipeline is destroyed. */
4729 __mmplayer_release_misc_post(player);
4731 /* release attributes */
4732 _mmplayer_deconstruct_attribute(handle);
4735 g_mutex_clear(&player->fsink_lock);
4738 g_mutex_clear(&player->update_tag_lock);
4740 /* release video bo lock and cond */
4741 g_mutex_clear(&player->video_bo_mutex);
4742 g_cond_clear(&player->video_bo_cond);
4744 /* release media stream callback lock */
4745 g_mutex_clear(&player->media_stream_cb_lock);
4749 return MM_ERROR_NONE;
4753 _mmplayer_realize(MMHandleType hplayer)
4755 mm_player_t* player = (mm_player_t*)hplayer;
4758 MMHandleType attrs = 0;
4759 int ret = MM_ERROR_NONE;
4763 /* check player handle */
4764 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4766 /* check current state */
4767 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4769 attrs = MMPLAYER_GET_ATTRS(player);
4771 LOGE("fail to get attributes.\n");
4772 return MM_ERROR_PLAYER_INTERNAL;
4774 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4775 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4777 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4778 ret = __mmplayer_parse_profile((const char*)uri, param, &player->profile);
4780 if (ret != MM_ERROR_NONE) {
4781 LOGE("failed to parse profile");
4786 if (uri && (strstr(uri, "es_buff://"))) {
4787 if (strstr(uri, "es_buff://push_mode"))
4788 player->es_player_push_mode = TRUE;
4790 player->es_player_push_mode = FALSE;
4793 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4794 LOGW("mms protocol is not supported format.\n");
4795 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4798 if (MMPLAYER_IS_STREAMING(player))
4799 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4801 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4803 player->smooth_streaming = FALSE;
4804 player->videodec_linked = 0;
4805 player->audiodec_linked = 0;
4806 player->textsink_linked = 0;
4807 player->is_external_subtitle_present = FALSE;
4808 player->is_external_subtitle_added_now = FALSE;
4809 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4810 player->video360_metadata.is_spherical = -1;
4811 player->is_openal_plugin_used = FALSE;
4812 player->demux_pad_index = 0;
4813 player->subtitle_language_list = NULL;
4814 player->is_subtitle_force_drop = FALSE;
4815 player->last_multiwin_status = FALSE;
4817 __mmplayer_track_initialize(player);
4818 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4820 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4821 player->streamer = __mm_player_streaming_create();
4822 __mm_player_streaming_initialize(player->streamer);
4825 /* realize pipeline */
4826 ret = __mmplayer_gst_realize(player);
4827 if (ret != MM_ERROR_NONE)
4828 LOGE("fail to realize the player.\n");
4830 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4838 _mmplayer_unrealize(MMHandleType hplayer)
4840 mm_player_t* player = (mm_player_t*)hplayer;
4841 int ret = MM_ERROR_NONE;
4845 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4847 MMPLAYER_CMD_UNLOCK(player);
4848 /* destroy the gst bus msg thread which is created during realize.
4849 this funct have to be called before getting cmd lock. */
4850 __mmplayer_bus_msg_thread_destroy(player);
4851 MMPLAYER_CMD_LOCK(player);
4853 /* check current state */
4854 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4856 /* check async state transition */
4857 __mmplayer_check_async_state_transition(player);
4859 /* unrealize pipeline */
4860 ret = __mmplayer_gst_unrealize(player);
4862 /* set asm stop if success */
4863 if (MM_ERROR_NONE == ret) {
4864 if (!player->interrupted_by_resource) {
4865 if (player->video_decoder_resource != NULL) {
4866 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4867 player->video_decoder_resource);
4868 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4869 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
4871 player->video_decoder_resource = NULL;
4874 if (player->video_overlay_resource != NULL) {
4875 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4876 player->video_overlay_resource);
4877 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4878 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
4880 player->video_overlay_resource = NULL;
4883 ret = mm_resource_manager_commit(player->resource_manager);
4884 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4885 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
4888 LOGE("failed and don't change asm state to stop");
4896 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
4898 mm_player_t* player = (mm_player_t*)hplayer;
4900 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4902 return __mmplayer_gst_set_message_callback(player, callback, user_param);
4906 _mmplayer_get_state(MMHandleType hplayer, int* state)
4908 mm_player_t *player = (mm_player_t*)hplayer;
4910 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
4912 *state = MMPLAYER_CURRENT_STATE(player);
4914 return MM_ERROR_NONE;
4919 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
4921 mm_player_t* player = (mm_player_t*) hplayer;
4922 GstElement* vol_element = NULL;
4927 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4929 LOGD("volume [L]=%f:[R]=%f\n",
4930 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
4932 /* invalid factor range or not */
4933 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
4934 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
4935 LOGE("Invalid factor!(valid factor:0~1.0)\n");
4936 return MM_ERROR_INVALID_ARGUMENT;
4940 /* not support to set other value into each channel */
4941 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
4942 return MM_ERROR_INVALID_ARGUMENT;
4944 /* Save volume to handle. Currently the first array element will be saved. */
4945 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
4947 /* check pipeline handle */
4948 if (!player->pipeline || !player->pipeline->audiobin) {
4949 LOGD("audiobin is not created yet\n");
4950 LOGD("but, current stored volume will be set when it's created.\n");
4952 /* NOTE : stored volume will be used in create_audiobin
4953 * returning MM_ERROR_NONE here makes application to able to
4954 * set volume at anytime.
4956 return MM_ERROR_NONE;
4959 /* setting volume to volume element */
4960 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
4963 LOGD("volume is set [%f]\n", player->sound.volume);
4964 g_object_set(vol_element, "volume", player->sound.volume, NULL);
4969 return MM_ERROR_NONE;
4974 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
4976 mm_player_t* player = (mm_player_t*) hplayer;
4981 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4982 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
4984 /* returning stored volume */
4985 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
4986 volume->level[i] = player->sound.volume;
4990 return MM_ERROR_NONE;
4994 _mmplayer_set_mute(MMHandleType hplayer, int mute)
4996 mm_player_t* player = (mm_player_t*) hplayer;
4997 GstElement* vol_element = NULL;
5001 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5003 /* mute value shoud 0 or 1 */
5004 if (mute != 0 && mute != 1) {
5005 LOGE("bad mute value\n");
5007 /* FIXIT : definitly, we need _BAD_PARAM error code */
5008 return MM_ERROR_INVALID_ARGUMENT;
5011 player->sound.mute = mute;
5013 /* just hold mute value if pipeline is not ready */
5014 if (!player->pipeline || !player->pipeline->audiobin) {
5015 LOGD("pipeline is not ready. holding mute value\n");
5016 return MM_ERROR_NONE;
5019 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5021 /* NOTE : volume will only created when the bt is enabled */
5023 LOGD("mute : %d\n", mute);
5024 g_object_set(vol_element, "mute", mute, NULL);
5026 LOGD("volume elemnet is not created. using volume in audiosink\n");
5030 return MM_ERROR_NONE;
5034 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
5036 mm_player_t* player = (mm_player_t*) hplayer;
5040 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5041 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5043 /* just hold mute value if pipeline is not ready */
5044 if (!player->pipeline || !player->pipeline->audiobin) {
5045 LOGD("pipeline is not ready. returning stored value\n");
5046 *pmute = player->sound.mute;
5047 return MM_ERROR_NONE;
5050 *pmute = player->sound.mute;
5054 return MM_ERROR_NONE;
5058 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5060 mm_player_t* player = (mm_player_t*) hplayer;
5064 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5066 player->video_stream_changed_cb = callback;
5067 player->video_stream_changed_cb_user_param = user_param;
5068 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
5072 return MM_ERROR_NONE;
5076 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5078 mm_player_t* player = (mm_player_t*) hplayer;
5082 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5084 player->audio_stream_changed_cb = callback;
5085 player->audio_stream_changed_cb_user_param = user_param;
5086 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
5090 return MM_ERROR_NONE;
5094 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5096 mm_player_t *player = (mm_player_t*) hplayer;
5100 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5102 player->audio_stream_render_cb = callback;
5103 player->audio_stream_cb_user_param = user_param;
5104 player->audio_stream_sink_sync = sync;
5105 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5109 return MM_ERROR_NONE;
5113 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5115 mm_player_t* player = (mm_player_t*) hplayer;
5119 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5121 if (callback && !player->bufmgr)
5122 player->bufmgr = tbm_bufmgr_init(-1);
5124 player->set_mode.media_packet_video_stream = (callback) ? true : false;
5125 player->video_stream_cb = callback;
5126 player->video_stream_cb_user_param = user_param;
5128 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5132 return MM_ERROR_NONE;
5136 _mmplayer_start(MMHandleType hplayer)
5138 mm_player_t* player = (mm_player_t*) hplayer;
5139 gint ret = MM_ERROR_NONE;
5143 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5145 /* check current state */
5146 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5148 /* start pipeline */
5149 ret = __mmplayer_gst_start(player);
5150 if (ret != MM_ERROR_NONE)
5151 LOGE("failed to start player.\n");
5153 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5154 LOGD("force playing start even during buffering");
5155 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5163 /* NOTE: post "not supported codec message" to application
5164 * when one codec is not found during AUTOPLUGGING in MSL.
5165 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5166 * And, if any codec is not found, don't send message here.
5167 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5170 __mmplayer_handle_missed_plugin(mm_player_t* player)
5172 MMMessageParamType msg_param;
5173 memset(&msg_param, 0, sizeof(MMMessageParamType));
5174 gboolean post_msg_direct = FALSE;
5178 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5180 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
5181 player->not_supported_codec, player->can_support_codec);
5183 if (player->not_found_demuxer) {
5184 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5185 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5187 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5188 MMPLAYER_FREEIF(msg_param.data);
5190 return MM_ERROR_NONE;
5193 if (player->not_supported_codec) {
5194 if (player->can_support_codec) {
5195 // There is one codec to play
5196 post_msg_direct = TRUE;
5198 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5199 post_msg_direct = TRUE;
5202 if (post_msg_direct) {
5203 MMMessageParamType msg_param;
5204 memset(&msg_param, 0, sizeof(MMMessageParamType));
5206 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5207 LOGW("not found AUDIO codec, posting error code to application.\n");
5209 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5210 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5211 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5212 LOGW("not found VIDEO codec, posting error code to application.\n");
5214 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5215 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5218 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5220 MMPLAYER_FREEIF(msg_param.data);
5222 return MM_ERROR_NONE;
5224 // no any supported codec case
5225 LOGW("not found any codec, posting error code to application.\n");
5227 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5228 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5229 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5231 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5232 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5235 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5237 MMPLAYER_FREEIF(msg_param.data);
5243 return MM_ERROR_NONE;
5246 static void __mmplayer_check_pipeline(mm_player_t* player)
5248 GstState element_state = GST_STATE_VOID_PENDING;
5249 GstState element_pending_state = GST_STATE_VOID_PENDING;
5251 int ret = MM_ERROR_NONE;
5253 if (player->gapless.reconfigure) {
5254 LOGW("pipeline is under construction.\n");
5256 MMPLAYER_PLAYBACK_LOCK(player);
5257 MMPLAYER_PLAYBACK_UNLOCK(player);
5259 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5261 /* wait for state transition */
5262 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5264 if (ret == GST_STATE_CHANGE_FAILURE)
5265 LOGE("failed to change pipeline state within %d sec\n", timeout);
5269 /* NOTE : it should be able to call 'stop' anytime*/
5271 _mmplayer_stop(MMHandleType hplayer)
5273 mm_player_t* player = (mm_player_t*)hplayer;
5274 int ret = MM_ERROR_NONE;
5278 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5280 /* check current state */
5281 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5283 /* check pipline building state */
5284 __mmplayer_check_pipeline(player);
5285 __mmplayer_reset_gapless_state(player);
5287 /* NOTE : application should not wait for EOS after calling STOP */
5288 __mmplayer_cancel_eos_timer(player);
5291 player->seek_state = MMPLAYER_SEEK_NONE;
5294 ret = __mmplayer_gst_stop(player);
5296 if (ret != MM_ERROR_NONE)
5297 LOGE("failed to stop player.\n");
5305 _mmplayer_pause(MMHandleType hplayer)
5307 mm_player_t* player = (mm_player_t*)hplayer;
5308 gint64 pos_nsec = 0;
5309 gboolean async = FALSE;
5310 gint ret = MM_ERROR_NONE;
5314 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5316 /* check current state */
5317 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5319 /* check pipline building state */
5320 __mmplayer_check_pipeline(player);
5322 switch (MMPLAYER_CURRENT_STATE(player)) {
5323 case MM_PLAYER_STATE_READY:
5325 /* check prepare async or not.
5326 * In the case of streaming playback, it's recommned to avoid blocking wait.
5328 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5329 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5331 /* Changing back sync of rtspsrc to async */
5332 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5333 LOGD("async prepare working mode for rtsp");
5339 case MM_PLAYER_STATE_PLAYING:
5341 /* NOTE : store current point to overcome some bad operation
5342 *(returning zero when getting current position in paused state) of some
5345 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5346 LOGW("getting current position failed in paused\n");
5348 player->last_position = pos_nsec;
5350 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5351 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5352 This causes problem is position calculation during normal pause resume scenarios also.
5353 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5354 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5355 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5356 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5362 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5363 LOGD("doing async pause in case of ms buff src");
5367 /* pause pipeline */
5368 ret = __mmplayer_gst_pause(player, async);
5370 if (ret != MM_ERROR_NONE)
5371 LOGE("failed to pause player. ret : 0x%x\n", ret);
5373 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5374 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5375 LOGE("failed to update display_rotation");
5383 /* in case of streaming, pause could take long time.*/
5385 _mmplayer_abort_pause(MMHandleType hplayer)
5387 mm_player_t* player = (mm_player_t*)hplayer;
5388 int ret = MM_ERROR_NONE;
5392 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5394 player->pipeline->mainbin,
5395 MM_ERROR_PLAYER_NOT_INITIALIZED);
5397 LOGD("set the pipeline state to READY");
5399 /* set state to READY */
5400 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5401 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5402 if (ret != MM_ERROR_NONE) {
5403 LOGE("fail to change state to READY");
5404 return MM_ERROR_PLAYER_INTERNAL;
5407 LOGD("succeeded in changing state to READY");
5413 _mmplayer_resume(MMHandleType hplayer)
5415 mm_player_t* player = (mm_player_t*)hplayer;
5416 int ret = MM_ERROR_NONE;
5417 gboolean async = FALSE;
5421 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5423 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5424 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5425 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5429 /* Changing back sync mode rtspsrc to async */
5430 LOGD("async resume for rtsp case");
5434 /* check current state */
5435 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5437 ret = __mmplayer_gst_resume(player, async);
5438 if (ret != MM_ERROR_NONE)
5439 LOGE("failed to resume player.\n");
5441 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5442 LOGD("force resume even during buffering");
5443 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5452 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5454 mm_player_t* player = (mm_player_t*)hplayer;
5455 gint64 pos_nsec = 0;
5456 int ret = MM_ERROR_NONE;
5458 signed long long start = 0, stop = 0;
5459 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5462 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5463 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5465 /* The sound of video is not supported under 0.0 and over 2.0. */
5466 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5467 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5470 _mmplayer_set_mute(hplayer, mute);
5472 if (player->playback_rate == rate)
5473 return MM_ERROR_NONE;
5475 /* If the position is reached at start potion during fast backward, EOS is posted.
5476 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5478 player->playback_rate = rate;
5480 current_state = MMPLAYER_CURRENT_STATE(player);
5482 if (current_state != MM_PLAYER_STATE_PAUSED)
5483 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5485 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5487 if ((current_state == MM_PLAYER_STATE_PAUSED)
5488 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5489 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5490 pos_nsec = player->last_position;
5495 stop = GST_CLOCK_TIME_NONE;
5497 start = GST_CLOCK_TIME_NONE;
5501 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5502 player->playback_rate,
5504 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5505 GST_SEEK_TYPE_SET, start,
5506 GST_SEEK_TYPE_SET, stop)) {
5507 LOGE("failed to set speed playback\n");
5508 return MM_ERROR_PLAYER_SEEK;
5511 LOGD("succeeded to set speed playback as %0.1f\n", rate);
5515 return MM_ERROR_NONE;;
5519 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5521 mm_player_t* player = (mm_player_t*)hplayer;
5522 int ret = MM_ERROR_NONE;
5526 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5528 /* check pipline building state */
5529 __mmplayer_check_pipeline(player);
5531 ret = __mmplayer_gst_set_position(player, position, FALSE);
5539 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5541 mm_player_t* player = (mm_player_t*)hplayer;
5542 int ret = MM_ERROR_NONE;
5544 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5546 ret = __mmplayer_gst_get_position(player, position);
5552 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5554 mm_player_t* player = (mm_player_t*)hplayer;
5555 int ret = MM_ERROR_NONE;
5557 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5558 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5560 *duration = player->duration;
5565 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5567 mm_player_t *player = (mm_player_t*)hplayer;
5568 int ret = MM_ERROR_NONE;
5570 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5572 ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5578 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5580 mm_player_t* player = (mm_player_t*)hplayer;
5581 int ret = MM_ERROR_NONE;
5585 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5587 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5595 __mmplayer_is_midi_type(gchar* str_caps)
5597 if ((g_strrstr(str_caps, "audio/midi")) ||
5598 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5599 (g_strrstr(str_caps, "application/x-smaf")) ||
5600 (g_strrstr(str_caps, "audio/x-imelody")) ||
5601 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5602 (g_strrstr(str_caps, "audio/xmf")) ||
5603 (g_strrstr(str_caps, "audio/mxmf"))) {
5612 __mmplayer_is_only_mp3_type(gchar *str_caps)
5614 if (g_strrstr(str_caps, "application/x-id3") ||
5615 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5621 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
5623 GstStructure* caps_structure = NULL;
5624 gint samplerate = 0;
5628 MMPLAYER_RETURN_IF_FAIL(player && caps);
5630 caps_structure = gst_caps_get_structure(caps, 0);
5632 /* set stream information */
5633 gst_structure_get_int(caps_structure, "rate", &samplerate);
5634 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5636 gst_structure_get_int(caps_structure, "channels", &channels);
5637 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5639 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
5643 __mmplayer_update_content_type_info(mm_player_t* player)
5646 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5648 if (__mmplayer_is_midi_type(player->type)) {
5649 player->bypass_audio_effect = TRUE;
5650 } else if (g_strrstr(player->type, "application/x-hls")) {
5651 /* If it can't know exact type when it parses uri because of redirection case,
5652 * it will be fixed by typefinder or when doing autoplugging.
5654 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5655 if (player->streamer) {
5656 player->streamer->is_adaptive_streaming = TRUE;
5657 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5658 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
5660 } else if (g_strrstr(player->type, "application/dash+xml")) {
5661 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5662 if (player->streamer) {
5663 player->streamer->is_adaptive_streaming = TRUE;
5664 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5668 LOGD("uri type : %d", player->profile.uri_type);
5673 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5674 GstCaps *caps, gpointer data)
5676 mm_player_t* player = (mm_player_t*)data;
5681 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5683 /* store type string */
5684 MMPLAYER_FREEIF(player->type);
5685 player->type = gst_caps_to_string(caps);
5687 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
5688 player, player->type, probability, gst_caps_get_size(caps));
5691 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5692 (g_strrstr(player->type, "audio/x-raw-int"))) {
5693 LOGE("not support media format\n");
5695 if (player->msg_posted == FALSE) {
5696 MMMessageParamType msg_param;
5697 memset(&msg_param, 0, sizeof(MMMessageParamType));
5699 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5700 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5702 /* don't post more if one was sent already */
5703 player->msg_posted = TRUE;
5708 __mmplayer_update_content_type_info(player);
5710 pad = gst_element_get_static_pad(tf, "src");
5712 LOGE("fail to get typefind src pad.\n");
5716 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5717 gboolean async = FALSE;
5718 LOGE("failed to autoplug %s\n", player->type);
5720 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5722 if (async && player->msg_posted == FALSE)
5723 __mmplayer_handle_missed_plugin(player);
5729 gst_object_unref(GST_OBJECT(pad));
5737 __mmplayer_gst_make_decodebin(mm_player_t* player)
5739 GstElement *decodebin = NULL;
5743 /* create decodebin */
5744 decodebin = gst_element_factory_make("decodebin", NULL);
5747 LOGE("fail to create decodebin\n");
5751 /* raw pad handling signal */
5752 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5753 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5755 /* no-more-pad pad handling signal */
5756 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5757 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5759 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5760 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5762 /* This signal is emitted when a pad for which there is no further possible
5763 decoding is added to the decodebin.*/
5764 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5765 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5767 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5768 before looking for any elements that can handle that stream.*/
5769 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5770 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5772 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5773 before looking for any elements that can handle that stream.*/
5774 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5775 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5777 /* This signal is emitted once decodebin has finished decoding all the data.*/
5778 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5779 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5781 /* This signal is emitted when a element is added to the bin.*/
5782 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5783 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5790 __mmplayer_gst_make_queue2(mm_player_t *player)
5792 GstElement* queue2 = NULL;
5793 gint64 dur_bytes = 0L;
5794 guint max_buffer_size_bytes = 0;
5795 MMPlayerGstElement *mainbin = NULL;
5796 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5799 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5801 mainbin = player->pipeline->mainbin;
5803 queue2 = gst_element_factory_make("queue2", "queue2");
5805 LOGE("failed to create buffering queue element");
5809 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5810 LOGE("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5812 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5814 if (dur_bytes > 0) {
5815 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
5816 type = MUXED_BUFFER_TYPE_FILE;
5818 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5819 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5825 /* NOTE : in case of ts streaming, player cannot get the correct duration info *
5826 * skip the pull mode(file or ring buffering) setting. */
5827 if (!g_strrstr(player->type, "video/mpegts")) {
5828 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
5829 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
5831 __mm_player_streaming_set_queue2(player->streamer,
5834 max_buffer_size_bytes,
5835 player->ini.http_buffering_time,
5837 player->http_file_buffering_path,
5838 (guint64)dur_bytes);
5845 __mmplayer_gst_create_decoder(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
5847 MMPlayerGstElement* mainbin = NULL;
5848 GstElement* decodebin = NULL;
5849 GstElement* queue2 = NULL;
5850 GstPad* sinkpad = NULL;
5851 GstPad* qsrcpad = NULL;
5852 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
5855 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
5857 mainbin = player->pipeline->mainbin;
5859 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
5861 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
5862 LOGW("need to check: muxed buffer is not null");
5865 queue2 = __mmplayer_gst_make_queue2(player);
5867 LOGE("failed to make queue2");
5871 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
5872 LOGE("failed to add buffering queue");
5876 sinkpad = gst_element_get_static_pad(queue2, "sink");
5877 qsrcpad = gst_element_get_static_pad(queue2, "src");
5879 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
5880 LOGE("failed to link [%s:%s]-[%s:%s]",
5881 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5885 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
5886 LOGE("failed to sync queue2 state with parent");
5890 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
5891 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
5895 gst_object_unref(GST_OBJECT(sinkpad));
5899 /* create decodebin */
5900 decodebin = __mmplayer_gst_make_decodebin(player);
5902 LOGE("failed to make decodebin");
5906 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
5907 LOGE("failed to add decodebin\n");
5911 /* to force caps on the decodebin element and avoid reparsing stuff by
5912 * typefind. It also avoids a deadlock in the way typefind activates pads in
5913 * the state change */
5914 g_object_set(decodebin, "sink-caps", caps, NULL);
5916 sinkpad = gst_element_get_static_pad(decodebin, "sink");
5918 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
5919 LOGE("failed to link [%s:%s]-[%s:%s]",
5920 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5924 gst_object_unref(GST_OBJECT(sinkpad));
5927 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
5928 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
5930 /* set decodebin property about buffer in streaming playback. *
5931 * in case of HLS/DASH, it does not need to have big buffer *
5932 * because it is kind of adaptive streaming. */
5933 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
5934 gdouble high_percent = 0.0;
5936 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
5937 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
5939 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
5940 GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
5942 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
5943 "high-percent", (gint)high_percent,
5944 "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
5945 "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
5946 "max-size-buffers", 0, NULL); // disable or automatic
5949 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
5950 LOGE("failed to sync decodebin state with parent\n");
5961 gst_object_unref(GST_OBJECT(sinkpad));
5964 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
5965 * You need to explicitly set elements to the NULL state before
5966 * dropping the final reference, to allow them to clean up.
5968 gst_element_set_state(queue2, GST_STATE_NULL);
5970 /* And, it still has a parent "player".
5971 * You need to let the parent manage the object instead of unreffing the object directly.
5973 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
5974 gst_object_unref(queue2);
5979 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
5980 * You need to explicitly set elements to the NULL state before
5981 * dropping the final reference, to allow them to clean up.
5983 gst_element_set_state(decodebin, GST_STATE_NULL);
5985 /* And, it still has a parent "player".
5986 * You need to let the parent manage the object instead of unreffing the object directly.
5989 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
5990 gst_object_unref(decodebin);
5998 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
6002 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6003 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6005 LOGD("class : %s, mime : %s \n", factory_class, mime);
6007 /* add missing plugin */
6008 /* NOTE : msl should check missing plugin for image mime type.
6009 * Some motion jpeg clips can have playable audio track.
6010 * So, msl have to play audio after displaying popup written video format not supported.
6012 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6013 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6014 LOGD("not found demuxer\n");
6015 player->not_found_demuxer = TRUE;
6016 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6022 if (!g_strrstr(factory_class, "Demuxer")) {
6023 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6024 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
6025 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6027 /* check that clip have multi tracks or not */
6028 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6029 LOGD("video plugin is already linked\n");
6031 LOGW("add VIDEO to missing plugin\n");
6032 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6033 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6035 } else if (g_str_has_prefix(mime, "audio")) {
6036 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6037 LOGD("audio plugin is already linked\n");
6039 LOGW("add AUDIO to missing plugin\n");
6040 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6041 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6049 return MM_ERROR_NONE;
6054 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6056 mm_player_t* player = (mm_player_t*)data;
6060 MMPLAYER_RETURN_IF_FAIL(player);
6062 /* remove fakesink. */
6063 if (!__mmplayer_gst_remove_fakesink(player,
6064 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6065 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6066 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6067 * source element are not same. To overcome this situation, this function will called
6068 * several places and several times. Therefore, this is not an error case.
6073 LOGD("[handle: %p] pipeline has completely constructed", player);
6075 if ((player->ini.async_start) &&
6076 (player->msg_posted == FALSE) &&
6077 (player->cmd >= MMPLAYER_COMMAND_START))
6078 __mmplayer_handle_missed_plugin(player);
6080 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6084 __mmplayer_check_profile(void)
6087 static int profile_tv = -1;
6089 if (__builtin_expect(profile_tv != -1, 1))
6092 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6093 switch (*profileName) {
6108 __mmplayer_get_next_uri(mm_player_t *player)
6110 MMPlayerParseProfile profile;
6112 guint num_of_list = 0;
6115 num_of_list = g_list_length(player->uri_info.uri_list);
6116 uri_idx = player->uri_info.uri_idx;
6118 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6119 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6120 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6122 LOGW("next uri does not exist");
6126 if (__mmplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
6127 LOGE("failed to parse profile");
6131 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6132 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6133 LOGW("uri type is not supported(%d)", profile.uri_type);
6137 LOGD("success to find next uri %d", uri_idx);
6141 if (uri_idx == num_of_list) {
6142 LOGE("failed to find next uri");
6146 player->uri_info.uri_idx = uri_idx;
6147 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6149 if (mm_attrs_commit_all(player->attrs)) {
6150 LOGE("failed to commit");
6154 SECURE_LOGD("next playback uri: %s", uri);
6159 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6161 #define REPEAT_COUNT_INFINITELY -1
6162 #define REPEAT_COUNT_MIN 2
6164 MMHandleType attrs = 0;
6168 guint num_of_list = 0;
6169 int profile_tv = -1;
6173 LOGD("checking for gapless play option");
6175 if (player->pipeline->textbin) {
6176 LOGE("subtitle path is enabled. gapless play is not supported.\n");
6180 attrs = MMPLAYER_GET_ATTRS(player);
6182 LOGE("fail to get attributes.\n");
6186 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6188 /* gapless playback is not supported in case of video at TV profile. */
6189 profile_tv = __mmplayer_check_profile();
6190 if (profile_tv && video) {
6191 LOGW("not support video gapless playback");
6195 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6196 LOGE("failed to get play count");
6198 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6199 LOGE("failed to get gapless mode");
6201 /* check repeat count in case of audio */
6203 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6204 LOGW("gapless is disabled");
6208 num_of_list = g_list_length(player->uri_info.uri_list);
6210 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6212 if (num_of_list == 0) {
6213 /* audio looping path */
6214 if (count >= REPEAT_COUNT_MIN) {
6215 /* decrease play count */
6216 /* we succeeded to rewind. update play count and then wait for next EOS */
6219 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6221 /* commit attribute */
6222 if (mm_attrs_commit_all(attrs))
6223 LOGE("failed to commit attribute");
6224 } else if (count != REPEAT_COUNT_INFINITELY) {
6225 LOGD("there is no next uri and no repeat");
6229 LOGD("looping cnt %d", count);
6231 /* gapless playback path */
6232 if (!__mmplayer_get_next_uri(player)) {
6233 LOGE("failed to get next uri");
6241 LOGE("unable to play gapless path. EOS will be posted soon");
6246 __mmplayer_initialize_gapless_play(mm_player_t *player)
6252 player->smooth_streaming = FALSE;
6253 player->videodec_linked = 0;
6254 player->audiodec_linked = 0;
6255 player->textsink_linked = 0;
6256 player->is_external_subtitle_present = FALSE;
6257 player->is_external_subtitle_added_now = FALSE;
6258 player->not_supported_codec = MISSING_PLUGIN_NONE;
6259 player->can_support_codec = FOUND_PLUGIN_NONE;
6260 player->pending_seek.is_pending = FALSE;
6261 player->pending_seek.pos = 0;
6262 player->msg_posted = FALSE;
6263 player->has_many_types = FALSE;
6264 player->no_more_pad = FALSE;
6265 player->not_found_demuxer = 0;
6266 player->seek_state = MMPLAYER_SEEK_NONE;
6267 player->is_subtitle_force_drop = FALSE;
6268 player->play_subtitle = FALSE;
6269 player->adjust_subtitle_pos = 0;
6271 player->total_bitrate = 0;
6272 player->total_maximum_bitrate = 0;
6274 __mmplayer_track_initialize(player);
6275 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6277 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6278 player->bitrate[i] = 0;
6279 player->maximum_bitrate[i] = 0;
6282 if (player->v_stream_caps) {
6283 gst_caps_unref(player->v_stream_caps);
6284 player->v_stream_caps = NULL;
6287 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6289 /* clean found parsers */
6290 if (player->parsers) {
6291 GList *parsers = player->parsers;
6292 for (; parsers; parsers = g_list_next(parsers)) {
6293 gchar *name = parsers->data;
6294 MMPLAYER_FREEIF(name);
6296 g_list_free(player->parsers);
6297 player->parsers = NULL;
6300 /* clean found audio decoders */
6301 if (player->audio_decoders) {
6302 GList *a_dec = player->audio_decoders;
6303 for (; a_dec; a_dec = g_list_next(a_dec)) {
6304 gchar *name = a_dec->data;
6305 MMPLAYER_FREEIF(name);
6307 g_list_free(player->audio_decoders);
6308 player->audio_decoders = NULL;
6315 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6317 MMPlayerGstElement *mainbin = NULL;
6318 MMMessageParamType msg_param = {0,};
6319 GstElement *element = NULL;
6320 MMHandleType attrs = 0;
6322 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6326 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6327 LOGE("player is not initialized");
6331 mainbin = player->pipeline->mainbin;
6332 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6334 attrs = MMPLAYER_GET_ATTRS(player);
6336 LOGE("fail to get attributes");
6340 /* Initialize Player values */
6341 __mmplayer_initialize_gapless_play(player);
6343 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6345 if (__mmplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6346 LOGE("failed to parse profile");
6347 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6351 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6352 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6353 LOGE("dash or hls is not supportable");
6354 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6358 element = __mmplayer_gst_create_source(player);
6360 LOGE("no source element was created");
6364 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6365 LOGE("failed to add source element to pipeline");
6366 gst_object_unref(GST_OBJECT(element));
6371 /* take source element */
6372 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6373 mainbin[MMPLAYER_M_SRC].gst = element;
6377 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6378 if (player->streamer == NULL) {
6379 player->streamer = __mm_player_streaming_create();
6380 __mm_player_streaming_initialize(player->streamer);
6383 elem_idx = MMPLAYER_M_TYPEFIND;
6384 element = gst_element_factory_make("typefind", "typefinder");
6385 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6386 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6388 elem_idx = MMPLAYER_M_AUTOPLUG;
6389 element = __mmplayer_gst_make_decodebin(player);
6392 /* check autoplug element is OK */
6394 LOGE("can not create element(%d)", elem_idx);
6398 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6399 LOGE("failed to add sinkbin to pipeline");
6400 gst_object_unref(GST_OBJECT(element));
6405 mainbin[elem_idx].id = elem_idx;
6406 mainbin[elem_idx].gst = element;
6408 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6409 LOGE("Failed to link src - autoplug(or typefind)");
6413 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6414 LOGE("Failed to change state of src element");
6418 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6419 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6420 LOGE("Failed to change state of decodebin");
6424 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6425 LOGE("Failed to change state of src element");
6430 player->gapless.stream_changed = TRUE;
6431 player->gapless.running = TRUE;
6437 MMPLAYER_PLAYBACK_UNLOCK(player);
6439 if (!player->msg_posted) {
6440 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6441 player->msg_posted = TRUE;
6448 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6450 mm_player_selector_t *selector = &player->selector[type];
6451 MMPlayerGstElement *sinkbin = NULL;
6452 enum MainElementID selectorId = MMPLAYER_M_NUM;
6453 enum MainElementID sinkId = MMPLAYER_M_NUM;
6454 GstPad *srcpad = NULL;
6455 GstPad *sinkpad = NULL;
6456 gboolean send_notice = FALSE;
6459 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6461 LOGD("type %d", type);
6464 case MM_PLAYER_TRACK_TYPE_AUDIO:
6465 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6466 sinkId = MMPLAYER_A_BIN;
6467 sinkbin = player->pipeline->audiobin;
6469 case MM_PLAYER_TRACK_TYPE_VIDEO:
6470 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6471 sinkId = MMPLAYER_V_BIN;
6472 sinkbin = player->pipeline->videobin;
6475 case MM_PLAYER_TRACK_TYPE_TEXT:
6476 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6477 sinkId = MMPLAYER_T_BIN;
6478 sinkbin = player->pipeline->textbin;
6481 LOGE("requested type is not supportable");
6486 if (player->pipeline->mainbin[selectorId].gst) {
6489 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6491 if (selector->event_probe_id != 0)
6492 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6493 selector->event_probe_id = 0;
6495 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6496 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6498 if (srcpad && sinkpad) {
6499 /* after getting drained signal there is no data flows, so no need to do pad_block */
6500 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6501 gst_pad_unlink(srcpad, sinkpad);
6503 /* send custom event to sink pad to handle it at video sink */
6505 LOGD("send custom event to sinkpad");
6506 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6507 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6508 gst_pad_send_event(sinkpad, event);
6512 gst_object_unref(sinkpad);
6515 gst_object_unref(srcpad);
6518 LOGD("selector release");
6520 /* release and unref requests pad from the selector */
6521 for (n = 0; n < selector->channels->len; n++) {
6522 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6523 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6525 g_ptr_array_set_size(selector->channels, 0);
6527 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6528 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6530 player->pipeline->mainbin[selectorId].gst = NULL;
6538 __mmplayer_deactivate_old_path(mm_player_t *player)
6541 MMPLAYER_RETURN_IF_FAIL(player);
6543 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6544 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6545 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6546 LOGE("deactivate selector error");
6550 __mmplayer_track_destroy(player);
6551 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6553 if (player->streamer) {
6554 __mm_player_streaming_deinitialize(player->streamer);
6555 __mm_player_streaming_destroy(player->streamer);
6556 player->streamer = NULL;
6559 MMPLAYER_PLAYBACK_LOCK(player);
6560 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6567 if (!player->msg_posted) {
6568 MMMessageParamType msg = {0,};
6571 msg.code = MM_ERROR_PLAYER_INTERNAL;
6572 LOGE("gapless_uri_play> deactivate error");
6574 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6575 player->msg_posted = TRUE;
6580 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
6582 int result = MM_ERROR_NONE;
6583 mm_player_t* player = (mm_player_t*) hplayer;
6586 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6589 player->http_file_buffering_path = (gchar*)file_path;
6590 LOGD("temp file path: %s\n", player->http_file_buffering_path);
6596 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
6598 int result = MM_ERROR_NONE;
6599 mm_player_t* player = (mm_player_t*) hplayer;
6602 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6604 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6605 if (mm_attrs_commit_all(player->attrs)) {
6606 LOGE("failed to commit the original uri.\n");
6607 result = MM_ERROR_PLAYER_INTERNAL;
6609 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6610 LOGE("failed to add the original uri in the uri list.\n");
6617 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
6619 mm_player_t* player = (mm_player_t*) hplayer;
6620 guint num_of_list = 0;
6624 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6625 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6627 if (player->pipeline && player->pipeline->textbin) {
6628 LOGE("subtitle path is enabled.\n");
6629 return MM_ERROR_PLAYER_INVALID_STATE;
6632 num_of_list = g_list_length(player->uri_info.uri_list);
6634 if (is_first_path == TRUE) {
6635 if (num_of_list == 0) {
6636 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6637 LOGD("add original path : %s", uri);
6639 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6640 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6642 LOGD("change original path : %s", uri);
6645 MMHandleType attrs = 0;
6646 attrs = MMPLAYER_GET_ATTRS(player);
6648 if (num_of_list == 0) {
6649 char *original_uri = NULL;
6652 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6654 if (!original_uri) {
6655 LOGE("there is no original uri.");
6656 return MM_ERROR_PLAYER_INVALID_STATE;
6659 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6660 player->uri_info.uri_idx = 0;
6662 LOGD("add original path at first : %s", original_uri);
6666 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6667 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6671 return MM_ERROR_NONE;
6674 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
6676 mm_player_t* player = (mm_player_t*) hplayer;
6677 char *next_uri = NULL;
6678 guint num_of_list = 0;
6681 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6683 num_of_list = g_list_length(player->uri_info.uri_list);
6685 if (num_of_list > 0) {
6686 gint uri_idx = player->uri_info.uri_idx;
6688 if (uri_idx < num_of_list-1)
6693 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6694 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
6696 *uri = g_strdup(next_uri);
6700 return MM_ERROR_NONE;
6704 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
6705 GstCaps *caps, gpointer data)
6707 mm_player_t* player = (mm_player_t*)data;
6708 const gchar* klass = NULL;
6709 const gchar* mime = NULL;
6710 gchar* caps_str = NULL;
6712 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6713 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6714 caps_str = gst_caps_to_string(caps);
6716 LOGW("unknown type of caps : %s from %s",
6717 caps_str, GST_ELEMENT_NAME(elem));
6719 MMPLAYER_FREEIF(caps_str);
6721 /* There is no available codec. */
6722 __mmplayer_check_not_supported_codec(player, klass, mime);
6726 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
6727 GstCaps * caps, gpointer data)
6729 mm_player_t* player = (mm_player_t*)data;
6730 const char* mime = NULL;
6731 gboolean ret = TRUE;
6733 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6734 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6736 if (g_str_has_prefix(mime, "audio")) {
6737 GstStructure* caps_structure = NULL;
6738 gint samplerate = 0;
6740 gchar *caps_str = NULL;
6742 caps_structure = gst_caps_get_structure(caps, 0);
6743 gst_structure_get_int(caps_structure, "rate", &samplerate);
6744 gst_structure_get_int(caps_structure, "channels", &channels);
6746 if ((channels > 0 && samplerate == 0)) {
6747 LOGD("exclude audio...");
6751 caps_str = gst_caps_to_string(caps);
6752 /* set it directly because not sent by TAG */
6753 if (g_strrstr(caps_str, "mobile-xmf"))
6754 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6755 MMPLAYER_FREEIF(caps_str);
6756 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6757 MMMessageParamType msg_param;
6758 memset(&msg_param, 0, sizeof(MMMessageParamType));
6759 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6760 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6761 LOGD("video file is not supported on this device");
6763 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6764 LOGD("already video linked");
6767 LOGD("found new stream");
6774 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
6776 int ret = MM_ERROR_NONE;
6778 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6780 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6781 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6783 LOGD("audio codec type: %d", codec_type);
6784 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6785 /* sw codec will be skipped */
6786 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6787 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6788 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6789 ret = MM_ERROR_PLAYER_INTERNAL;
6793 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6794 /* hw codec will be skipped */
6795 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6796 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6797 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6798 ret = MM_ERROR_PLAYER_INTERNAL;
6803 /* set stream information */
6804 if (!player->audiodec_linked)
6805 __mmplayer_set_audio_attrs(player, caps);
6807 /* update codec info */
6808 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6809 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6810 player->audiodec_linked = 1;
6812 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6814 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6816 LOGD("video codec type: %d", codec_type);
6817 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6818 /* sw codec is skipped */
6819 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
6820 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
6821 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
6822 ret = MM_ERROR_PLAYER_INTERNAL;
6826 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6827 /* hw codec is skipped */
6828 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
6829 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
6830 ret = MM_ERROR_PLAYER_INTERNAL;
6835 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
6836 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
6838 /* mark video decoder for acquire */
6839 if (player->video_decoder_resource == NULL) {
6840 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
6841 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
6842 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
6843 &player->video_decoder_resource)
6844 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6845 LOGE("could not mark video_decoder resource for acquire");
6846 ret = MM_ERROR_PLAYER_INTERNAL;
6850 LOGW("video decoder resource is already acquired, skip it.");
6851 ret = MM_ERROR_PLAYER_INTERNAL;
6855 player->interrupted_by_resource = FALSE;
6856 /* acquire resources for video playing */
6857 if (mm_resource_manager_commit(player->resource_manager)
6858 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6859 LOGE("could not acquire resources for video decoding\n");
6860 ret = MM_ERROR_PLAYER_INTERNAL;
6865 /* update codec info */
6866 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
6867 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
6868 player->videodec_linked = 1;
6876 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
6877 GstCaps* caps, GstElementFactory* factory, gpointer data)
6879 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
6880 We are defining our own and will be removed when it actually exposed */
6882 GST_AUTOPLUG_SELECT_TRY,
6883 GST_AUTOPLUG_SELECT_EXPOSE,
6884 GST_AUTOPLUG_SELECT_SKIP
6885 } GstAutoplugSelectResult;
6887 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
6888 mm_player_t* player = (mm_player_t*)data;
6890 gchar* factory_name = NULL;
6891 gchar* caps_str = NULL;
6892 const gchar* klass = NULL;
6895 factory_name = GST_OBJECT_NAME(factory);
6896 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
6897 caps_str = gst_caps_to_string(caps);
6899 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
6901 /* store type string */
6902 if (player->type == NULL) {
6903 player->type = gst_caps_to_string(caps);
6904 __mmplayer_update_content_type_info(player);
6907 /* filtering exclude keyword */
6908 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
6909 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
6910 LOGW("skipping [%s] by exculde keyword [%s]",
6911 factory_name, player->ini.exclude_element_keyword[idx]);
6913 result = GST_AUTOPLUG_SELECT_SKIP;
6918 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
6919 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
6920 LOGW("skipping [%s] by unsupported codec keyword [%s]",
6921 factory_name, player->ini.unsupported_codec_keyword[idx]);
6922 result = GST_AUTOPLUG_SELECT_SKIP;
6927 /* exclude webm format */
6928 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
6929 * because webm format is not supportable.
6930 * If webm is disabled in "autoplug-continue", there is no state change
6931 * failure or error because the decodebin will expose the pad directly.
6932 * It make MSL invoke _prepare_async_callback.
6933 * So, we need to disable webm format in "autoplug-select" */
6934 if (caps_str && strstr(caps_str, "webm")) {
6935 LOGW("webm is not supported");
6936 result = GST_AUTOPLUG_SELECT_SKIP;
6940 /* check factory class for filtering */
6941 /* NOTE : msl don't need to use image plugins.
6942 * So, those plugins should be skipped for error handling.
6944 if (g_strrstr(klass, "Codec/Decoder/Image")) {
6945 LOGD("skipping [%s] by not required\n", factory_name);
6946 result = GST_AUTOPLUG_SELECT_SKIP;
6950 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
6951 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
6952 // TO CHECK : subtitle if needed, add subparse exception.
6953 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
6954 result = GST_AUTOPLUG_SELECT_SKIP;
6958 if (g_strrstr(factory_name, "mpegpsdemux")) {
6959 LOGD("skipping PS container - not support\n");
6960 result = GST_AUTOPLUG_SELECT_SKIP;
6964 if (g_strrstr(factory_name, "mssdemux"))
6965 player->smooth_streaming = TRUE;
6967 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
6968 (g_strrstr(klass, "Codec/Decoder/Video"))) {
6971 GstStructure *str = NULL;
6972 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
6974 /* don't make video because of not required */
6975 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
6976 (!player->set_mode.media_packet_video_stream)) {
6977 LOGD("no need video decoding, expose pad");
6978 result = GST_AUTOPLUG_SELECT_EXPOSE;
6982 /* get w/h for omx state-tune */
6983 /* FIXME: deprecated? */
6984 str = gst_caps_get_structure(caps, 0);
6985 gst_structure_get_int(str, "width", &width);
6988 if (player->v_stream_caps) {
6989 gst_caps_unref(player->v_stream_caps);
6990 player->v_stream_caps = NULL;
6993 player->v_stream_caps = gst_caps_copy(caps);
6994 LOGD("take caps for video state tune");
6995 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
6999 if (g_strrstr(klass, "Codec/Decoder")) {
7000 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
7001 LOGD("skipping %s codec", factory_name);
7002 result = GST_AUTOPLUG_SELECT_SKIP;
7008 MMPLAYER_FREEIF(caps_str);
7014 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
7017 //mm_player_t* player = (mm_player_t*)data;
7018 GstCaps* caps = NULL;
7020 LOGD("[Decodebin2] pad-removed signal\n");
7022 caps = gst_pad_query_caps(new_pad, NULL);
7024 gchar* caps_str = NULL;
7025 caps_str = gst_caps_to_string(caps);
7027 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7029 MMPLAYER_FREEIF(caps_str);
7030 gst_caps_unref(caps);
7035 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7037 mm_player_t* player = (mm_player_t*)data;
7038 GstIterator *iter = NULL;
7039 GValue item = { 0, };
7041 gboolean done = FALSE;
7042 gboolean is_all_drained = TRUE;
7045 MMPLAYER_RETURN_IF_FAIL(player);
7047 LOGD("__mmplayer_gst_decode_drained");
7049 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7050 LOGW("Fail to get cmd lock");
7054 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7055 !__mmplayer_verify_gapless_play_path(player)) {
7056 LOGD("decoding is finished.");
7057 __mmplayer_reset_gapless_state(player);
7058 MMPLAYER_CMD_UNLOCK(player);
7062 player->gapless.reconfigure = TRUE;
7064 /* check decodebin src pads whether they received EOS or not */
7065 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7068 switch (gst_iterator_next(iter, &item)) {
7069 case GST_ITERATOR_OK:
7070 pad = g_value_get_object(&item);
7071 if (pad && !GST_PAD_IS_EOS(pad)) {
7072 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7073 is_all_drained = FALSE;
7076 g_value_reset(&item);
7078 case GST_ITERATOR_RESYNC:
7079 gst_iterator_resync(iter);
7081 case GST_ITERATOR_ERROR:
7082 case GST_ITERATOR_DONE:
7087 g_value_unset(&item);
7088 gst_iterator_free(iter);
7090 if (!is_all_drained) {
7091 LOGD("Wait util the all pads get EOS.");
7092 MMPLAYER_CMD_UNLOCK(player);
7097 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7098 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7100 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7101 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7102 __mmplayer_deactivate_old_path(player);
7103 MMPLAYER_CMD_UNLOCK(player);
7109 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7111 mm_player_t* player = (mm_player_t*)data;
7112 const gchar* klass = NULL;
7113 gchar* factory_name = NULL;
7115 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7116 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7118 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
7120 if (__mmplayer_add_dump_buffer_probe(player, element))
7121 LOGD("add buffer probe");
7124 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7125 gchar* selected = NULL;
7126 selected = g_strdup(GST_ELEMENT_NAME(element));
7127 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7131 if (g_strrstr(klass, "Parser")) {
7132 gchar* selected = NULL;
7134 selected = g_strdup(factory_name);
7135 player->parsers = g_list_append(player->parsers, selected);
7138 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7139 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7140 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7142 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7143 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7145 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7146 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7147 "max-video-width", player->adaptive_info.limit.width,
7148 "max-video-height", player->adaptive_info.limit.height, NULL);
7150 } else if (g_strrstr(klass, "Demuxer")) {
7151 //LOGD("plugged element is demuxer. take it");
7152 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7153 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7156 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7157 int surface_type = 0;
7159 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7162 // to support trust-zone only
7163 if (g_strrstr(factory_name, "asfdemux")) {
7164 LOGD("set file-location %s\n", player->profile.uri);
7165 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7166 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7167 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
7168 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7169 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7170 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7171 (__mmplayer_is_only_mp3_type(player->type))) {
7172 LOGD("[mpegaudioparse] set streaming pull mode.");
7173 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7175 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7176 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7179 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7180 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7181 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7183 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7184 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7186 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7187 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7188 (MMPLAYER_IS_DASH_STREAMING(player))) {
7189 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7190 __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time);
7191 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7200 __mmplayer_release_misc(mm_player_t* player)
7203 bool cur_mode = player->set_mode.rich_audio;
7206 MMPLAYER_RETURN_IF_FAIL(player);
7208 player->video_stream_cb = NULL;
7209 player->video_stream_cb_user_param = NULL;
7210 player->video_stream_prerolled = FALSE;
7212 player->audio_stream_render_cb = NULL;
7213 player->audio_stream_cb_user_param = NULL;
7214 player->audio_stream_sink_sync = false;
7216 player->video_stream_changed_cb = NULL;
7217 player->video_stream_changed_cb_user_param = NULL;
7219 player->audio_stream_changed_cb = NULL;
7220 player->audio_stream_changed_cb_user_param = NULL;
7222 player->sent_bos = FALSE;
7223 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7225 player->seek_state = MMPLAYER_SEEK_NONE;
7227 player->total_bitrate = 0;
7228 player->total_maximum_bitrate = 0;
7230 player->not_found_demuxer = 0;
7232 player->last_position = 0;
7233 player->duration = 0;
7234 player->http_content_size = 0;
7235 player->not_supported_codec = MISSING_PLUGIN_NONE;
7236 player->can_support_codec = FOUND_PLUGIN_NONE;
7237 player->pending_seek.is_pending = FALSE;
7238 player->pending_seek.pos = 0;
7239 player->msg_posted = FALSE;
7240 player->has_many_types = FALSE;
7241 player->is_subtitle_force_drop = FALSE;
7242 player->play_subtitle = FALSE;
7243 player->adjust_subtitle_pos = 0;
7244 player->last_multiwin_status = FALSE;
7245 player->has_closed_caption = FALSE;
7246 player->set_mode.media_packet_video_stream = false;
7247 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7248 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7250 player->set_mode.rich_audio = cur_mode;
7252 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7253 player->bitrate[i] = 0;
7254 player->maximum_bitrate[i] = 0;
7257 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7259 /* remove media stream cb(appsrc cb) */
7260 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7261 player->media_stream_buffer_status_cb[i] = NULL;
7262 player->media_stream_seek_data_cb[i] = NULL;
7263 player->buffer_cb_user_param[i] = NULL;
7264 player->seek_cb_user_param[i] = NULL;
7266 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7268 /* free memory related to audio effect */
7269 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7271 if (player->adaptive_info.var_list) {
7272 g_list_free_full(player->adaptive_info.var_list, g_free);
7273 player->adaptive_info.var_list = NULL;
7276 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7277 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7278 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7280 /* Reset video360 settings to their defaults in case if the pipeline is to be
7283 player->video360_metadata.is_spherical = -1;
7284 player->is_openal_plugin_used = FALSE;
7286 player->is_content_spherical = FALSE;
7287 player->is_video360_enabled = TRUE;
7288 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7289 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7290 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7291 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7292 player->video360_zoom = 1.0f;
7293 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7294 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7296 player->sound.rg_enable = false;
7298 __mmplayer_initialize_video_roi(player);
7303 __mmplayer_release_misc_post(mm_player_t* player)
7305 char *original_uri = NULL;
7308 /* player->pipeline is already released before. */
7310 MMPLAYER_RETURN_IF_FAIL(player);
7312 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7314 /* clean found parsers */
7315 if (player->parsers) {
7316 GList *parsers = player->parsers;
7317 for (; parsers; parsers = g_list_next(parsers)) {
7318 gchar *name = parsers->data;
7319 MMPLAYER_FREEIF(name);
7321 g_list_free(player->parsers);
7322 player->parsers = NULL;
7325 /* clean found audio decoders */
7326 if (player->audio_decoders) {
7327 GList *a_dec = player->audio_decoders;
7328 for (; a_dec; a_dec = g_list_next(a_dec)) {
7329 gchar *name = a_dec->data;
7330 MMPLAYER_FREEIF(name);
7332 g_list_free(player->audio_decoders);
7333 player->audio_decoders = NULL;
7336 /* clean the uri list except original uri */
7337 if (player->uri_info.uri_list) {
7338 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7340 if (player->attrs) {
7341 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7342 LOGD("restore original uri = %s\n", original_uri);
7344 if (mm_attrs_commit_all(player->attrs))
7345 LOGE("failed to commit the original uri.\n");
7348 GList *uri_list = player->uri_info.uri_list;
7349 for (; uri_list; uri_list = g_list_next(uri_list)) {
7350 gchar *uri = uri_list->data;
7351 MMPLAYER_FREEIF(uri);
7353 g_list_free(player->uri_info.uri_list);
7354 player->uri_info.uri_list = NULL;
7357 /* clear the audio stream buffer list */
7358 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7360 /* clear the video stream bo list */
7361 __mmplayer_video_stream_destroy_bo_list(player);
7362 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7364 if (player->profile.input_mem.buf) {
7365 free(player->profile.input_mem.buf);
7366 player->profile.input_mem.buf = NULL;
7368 player->profile.input_mem.len = 0;
7369 player->profile.input_mem.offset = 0;
7371 player->uri_info.uri_idx = 0;
7376 __mmplayer_check_subtitle(mm_player_t* player)
7378 MMHandleType attrs = 0;
7379 char *subtitle_uri = NULL;
7383 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7385 /* get subtitle attribute */
7386 attrs = MMPLAYER_GET_ATTRS(player);
7390 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7391 if (!subtitle_uri || !strlen(subtitle_uri))
7394 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7395 player->is_external_subtitle_present = TRUE;
7403 __mmplayer_cancel_eos_timer(mm_player_t* player)
7405 MMPLAYER_RETURN_IF_FAIL(player);
7407 if (player->eos_timer) {
7408 LOGD("cancel eos timer");
7409 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7410 player->eos_timer = 0;
7417 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
7421 MMPLAYER_RETURN_IF_FAIL(player);
7422 MMPLAYER_RETURN_IF_FAIL(sink);
7424 player->sink_elements =
7425 g_list_append(player->sink_elements, sink);
7431 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
7435 MMPLAYER_RETURN_IF_FAIL(player);
7436 MMPLAYER_RETURN_IF_FAIL(sink);
7438 player->sink_elements =
7439 g_list_remove(player->sink_elements, sink);
7445 __mmplayer_add_signal_connection(mm_player_t* player, GObject* object,
7446 MMPlayerSignalType type, const gchar* signal, GCallback cb_funct, gpointer u_data)
7448 MMPlayerSignalItem* item = NULL;
7451 MMPLAYER_RETURN_IF_FAIL(player);
7453 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7454 LOGE("invalid signal type [%d]", type);
7458 item = (MMPlayerSignalItem*)g_malloc(sizeof(MMPlayerSignalItem));
7460 LOGE("cannot connect signal [%s]", signal);
7465 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7466 player->signals[type] = g_list_append(player->signals[type], item);
7472 /* NOTE : be careful with calling this api. please refer to below glib comment
7473 * glib comment : Note that there is a bug in GObject that makes this function much
7474 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7475 * will no longer be called, but, the signal handler is not currently disconnected.
7476 * If the instance is itself being freed at the same time than this doesn't matter,
7477 * since the signal will automatically be removed, but if instance persists,
7478 * then the signal handler will leak. You should not remove the signal yourself
7479 * because in a future versions of GObject, the handler will automatically be
7482 * It's possible to work around this problem in a way that will continue to work
7483 * with future versions of GObject by checking that the signal handler is still
7484 * connected before disconnected it:
7486 * if (g_signal_handler_is_connected(instance, id))
7487 * g_signal_handler_disconnect(instance, id);
7490 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
7492 GList* sig_list = NULL;
7493 MMPlayerSignalItem* item = NULL;
7497 MMPLAYER_RETURN_IF_FAIL(player);
7499 LOGD("release signals type : %d", type);
7501 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7502 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7503 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7504 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7505 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7506 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7510 sig_list = player->signals[type];
7512 for (; sig_list; sig_list = sig_list->next) {
7513 item = sig_list->data;
7515 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7516 if (g_signal_handler_is_connected(item->obj, item->sig))
7517 g_signal_handler_disconnect(item->obj, item->sig);
7520 MMPLAYER_FREEIF(item);
7523 g_list_free(player->signals[type]);
7524 player->signals[type] = NULL;
7531 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7533 mm_player_t* player = 0;
7534 int prev_display_surface_type = 0;
7535 void *prev_display_overlay = NULL;
7539 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7540 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7542 player = MM_PLAYER_CAST(handle);
7544 /* check video sinkbin is created */
7545 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7546 LOGE("Videosink is already created");
7547 return MM_ERROR_NONE;
7550 LOGD("videosink element is not yet ready");
7552 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7553 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7555 return MM_ERROR_INVALID_ARGUMENT;
7558 /* load previous attributes */
7559 if (player->attrs) {
7560 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7561 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7562 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7563 if (prev_display_surface_type == surface_type) {
7564 LOGD("incoming display surface type is same as previous one, do nothing..");
7566 return MM_ERROR_NONE;
7569 LOGE("failed to load attributes");
7571 return MM_ERROR_PLAYER_INTERNAL;
7574 /* videobin is not created yet, so we just set attributes related to display surface */
7575 LOGD("store display attribute for given surface type(%d)", surface_type);
7576 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7577 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7578 if (mm_attrs_commit_all(player->attrs)) {
7579 LOGE("failed to commit attribute");
7581 return MM_ERROR_PLAYER_INTERNAL;
7585 return MM_ERROR_NONE;
7588 /* Note : if silent is true, then subtitle would not be displayed. :*/
7589 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7591 mm_player_t* player = (mm_player_t*) hplayer;
7595 /* check player handle */
7596 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7598 player->set_mode.subtitle_off = silent;
7600 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
7604 return MM_ERROR_NONE;
7607 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
7609 MMPlayerGstElement* mainbin = NULL;
7610 MMPlayerGstElement* textbin = NULL;
7611 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7612 GstState current_state = GST_STATE_VOID_PENDING;
7613 GstState element_state = GST_STATE_VOID_PENDING;
7614 GstState element_pending_state = GST_STATE_VOID_PENDING;
7616 GstEvent *event = NULL;
7617 int result = MM_ERROR_NONE;
7619 GstClock *curr_clock = NULL;
7620 GstClockTime base_time, start_time, curr_time;
7625 /* check player handle */
7626 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7628 player->pipeline->mainbin &&
7629 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7631 mainbin = player->pipeline->mainbin;
7632 textbin = player->pipeline->textbin;
7634 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7636 // sync clock with current pipeline
7637 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7638 curr_time = gst_clock_get_time(curr_clock);
7640 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7641 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7643 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7644 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7646 if (current_state > GST_STATE_READY) {
7647 // sync state with current pipeline
7648 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7649 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7650 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7652 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7653 if (GST_STATE_CHANGE_FAILURE == ret) {
7654 LOGE("fail to state change.\n");
7655 result = MM_ERROR_PLAYER_INTERNAL;
7659 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7660 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7663 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7664 gst_object_unref(curr_clock);
7667 // seek to current position
7668 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7669 result = MM_ERROR_PLAYER_INVALID_STATE;
7670 LOGE("gst_element_query_position failed, invalid state\n");
7674 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7675 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);
7677 __mmplayer_gst_send_event_to_sink(player, event);
7679 result = MM_ERROR_PLAYER_INTERNAL;
7680 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7684 /* sync state with current pipeline */
7685 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7686 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7687 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7689 return MM_ERROR_NONE;
7692 /* release text pipeline resource */
7693 player->textsink_linked = 0;
7695 /* release signal */
7696 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7698 /* release textbin with it's childs */
7699 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7700 MMPLAYER_FREEIF(player->pipeline->textbin);
7701 player->pipeline->textbin = NULL;
7703 /* release subtitle elem */
7704 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7705 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7711 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
7713 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7714 GstState current_state = GST_STATE_VOID_PENDING;
7716 MMHandleType attrs = 0;
7717 MMPlayerGstElement* mainbin = NULL;
7718 MMPlayerGstElement* textbin = NULL;
7720 gchar* subtitle_uri = NULL;
7721 int result = MM_ERROR_NONE;
7722 const gchar *charset = NULL;
7726 /* check player handle */
7727 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7729 player->pipeline->mainbin &&
7730 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7731 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7733 mainbin = player->pipeline->mainbin;
7734 textbin = player->pipeline->textbin;
7736 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7737 if (current_state < GST_STATE_READY) {
7738 result = MM_ERROR_PLAYER_INVALID_STATE;
7739 LOGE("Pipeline is not in proper state\n");
7743 attrs = MMPLAYER_GET_ATTRS(player);
7745 LOGE("cannot get content attribute\n");
7746 result = MM_ERROR_PLAYER_INTERNAL;
7750 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7751 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7752 LOGE("subtitle uri is not proper filepath\n");
7753 result = MM_ERROR_PLAYER_INVALID_URI;
7757 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7758 LOGE("failed to get storage info of subtitle path");
7759 result = MM_ERROR_PLAYER_INVALID_URI;
7763 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
7764 LOGD("new subtitle file path is [%s]\n", filepath);
7766 if (!strcmp(filepath, subtitle_uri)) {
7767 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
7770 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7771 if (mm_attrs_commit_all(player->attrs)) {
7772 LOGE("failed to commit.\n");
7777 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7778 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7779 player->subtitle_language_list = NULL;
7780 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7782 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7783 if (ret != GST_STATE_CHANGE_SUCCESS) {
7784 LOGE("failed to change state of textbin to READY");
7785 result = MM_ERROR_PLAYER_INTERNAL;
7789 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7790 if (ret != GST_STATE_CHANGE_SUCCESS) {
7791 LOGE("failed to change state of subparse to READY");
7792 result = MM_ERROR_PLAYER_INTERNAL;
7796 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7797 if (ret != GST_STATE_CHANGE_SUCCESS) {
7798 LOGE("failed to change state of filesrc to READY");
7799 result = MM_ERROR_PLAYER_INTERNAL;
7803 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7805 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7807 charset = util_get_charset(filepath);
7809 LOGD("detected charset is %s\n", charset);
7810 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7813 result = _mmplayer_sync_subtitle_pipeline(player);
7820 /* API to switch between external subtitles */
7821 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
7823 int result = MM_ERROR_NONE;
7824 mm_player_t* player = (mm_player_t*)hplayer;
7829 /* check player handle */
7830 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7832 /* filepath can be null in idle state */
7834 /* check file path */
7835 if ((path = strstr(filepath, "file://")))
7836 result = util_exist_file_path(path + 7);
7838 result = util_exist_file_path(filepath);
7840 if (result != MM_ERROR_NONE) {
7841 LOGE("invalid subtitle path 0x%X", result);
7842 return result; /* file not found or permission denied */
7846 if (!player->pipeline) {
7848 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7849 if (mm_attrs_commit_all(player->attrs)) {
7850 LOGE("failed to commit"); /* subtitle path will not be created */
7851 return MM_ERROR_PLAYER_INTERNAL;
7854 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7855 /* check filepath */
7856 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7858 if (!__mmplayer_check_subtitle(player)) {
7859 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7860 if (mm_attrs_commit_all(player->attrs)) {
7861 LOGE("failed to commit");
7862 return MM_ERROR_PLAYER_INTERNAL;
7865 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
7866 LOGE("fail to create text pipeline");
7867 return MM_ERROR_PLAYER_INTERNAL;
7870 result = _mmplayer_sync_subtitle_pipeline(player);
7872 result = __mmplayer_change_external_subtitle_language(player, filepath);
7875 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
7876 player->is_external_subtitle_added_now = TRUE;
7878 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7879 if (!player->subtitle_language_list) {
7880 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
7881 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
7882 LOGW("subtitle language list is not updated yet");
7884 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7892 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
7894 int result = MM_ERROR_NONE;
7895 gchar* change_pad_name = NULL;
7896 GstPad* sinkpad = NULL;
7897 MMPlayerGstElement* mainbin = NULL;
7898 enum MainElementID elem_idx = MMPLAYER_M_NUM;
7899 GstCaps* caps = NULL;
7900 gint total_track_num = 0;
7904 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
7905 MM_ERROR_PLAYER_NOT_INITIALIZED);
7907 LOGD("Change Track(%d) to %d\n", type, index);
7909 mainbin = player->pipeline->mainbin;
7911 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
7912 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
7913 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
7914 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
7916 /* Changing Video Track is not supported. */
7917 LOGE("Track Type Error\n");
7921 if (mainbin[elem_idx].gst == NULL) {
7922 result = MM_ERROR_PLAYER_NO_OP;
7923 LOGD("Req track doesn't exist\n");
7927 total_track_num = player->selector[type].total_track_num;
7928 if (total_track_num <= 0) {
7929 result = MM_ERROR_PLAYER_NO_OP;
7930 LOGD("Language list is not available \n");
7934 if ((index < 0) || (index >= total_track_num)) {
7935 result = MM_ERROR_INVALID_ARGUMENT;
7936 LOGD("Not a proper index : %d \n", index);
7940 /*To get the new pad from the selector*/
7941 change_pad_name = g_strdup_printf("sink_%u", index);
7942 if (change_pad_name == NULL) {
7943 result = MM_ERROR_PLAYER_INTERNAL;
7944 LOGD("Pad does not exists\n");
7948 LOGD("new active pad name: %s\n", change_pad_name);
7950 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
7951 if (sinkpad == NULL) {
7952 LOGD("sinkpad is NULL");
7953 result = MM_ERROR_PLAYER_INTERNAL;
7957 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
7958 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
7960 caps = gst_pad_get_current_caps(sinkpad);
7961 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
7964 gst_object_unref(sinkpad);
7966 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
7967 __mmplayer_set_audio_attrs(player, caps);
7971 MMPLAYER_FREEIF(change_pad_name);
7975 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
7977 int result = MM_ERROR_NONE;
7978 mm_player_t* player = NULL;
7979 MMPlayerGstElement* mainbin = NULL;
7981 gint current_active_index = 0;
7983 GstState current_state = GST_STATE_VOID_PENDING;
7984 GstEvent* event = NULL;
7989 player = (mm_player_t*)hplayer;
7990 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7992 if (!player->pipeline) {
7993 LOGE("Track %d pre setting -> %d\n", type, index);
7995 player->selector[type].active_pad_index = index;
7999 mainbin = player->pipeline->mainbin;
8001 current_active_index = player->selector[type].active_pad_index;
8003 /*If index is same as running index no need to change the pad*/
8004 if (current_active_index == index)
8007 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8008 result = MM_ERROR_PLAYER_INVALID_STATE;
8012 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8013 if (current_state < GST_STATE_PAUSED) {
8014 result = MM_ERROR_PLAYER_INVALID_STATE;
8015 LOGW("Pipeline not in porper state\n");
8019 result = __mmplayer_change_selector_pad(player, type, index);
8020 if (result != MM_ERROR_NONE) {
8021 LOGE("change selector pad error\n");
8025 player->selector[type].active_pad_index = index;
8027 if (current_state == GST_STATE_PLAYING) {
8028 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);
8030 __mmplayer_gst_send_event_to_sink(player, event);
8032 result = MM_ERROR_PLAYER_INTERNAL;
8041 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
8043 mm_player_t* player = (mm_player_t*) hplayer;
8047 /* check player handle */
8048 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8050 *silent = player->set_mode.subtitle_off;
8052 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
8056 return MM_ERROR_NONE;
8060 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8062 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8063 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8065 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8066 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8070 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8071 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8072 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8073 mm_player_dump_t *dump_s;
8074 dump_s = g_malloc(sizeof(mm_player_dump_t));
8076 if (dump_s == NULL) {
8077 LOGE("malloc fail");
8081 dump_s->dump_element_file = NULL;
8082 dump_s->dump_pad = NULL;
8083 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8085 if (dump_s->dump_pad) {
8086 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
8087 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]);
8088 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8089 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);
8090 /* add list for removed buffer probe and close FILE */
8091 player->dump_list = g_list_append(player->dump_list, dump_s);
8092 LOGD("%s sink pad added buffer probe for dump", factory_name);
8097 LOGE("failed to get %s sink pad added", factory_name);
8104 static GstPadProbeReturn
8105 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8107 FILE *dump_data = (FILE *) u_data;
8109 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8110 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8112 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
8114 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8116 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8118 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8120 return GST_PAD_PROBE_OK;
8124 __mmplayer_release_dump_list(GList *dump_list)
8127 GList *d_list = dump_list;
8128 for (; d_list; d_list = g_list_next(d_list)) {
8129 mm_player_dump_t *dump_s = d_list->data;
8130 if (dump_s->dump_pad) {
8131 if (dump_s->probe_handle_id)
8132 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8134 if (dump_s->dump_element_file) {
8135 fclose(dump_s->dump_element_file);
8136 dump_s->dump_element_file = NULL;
8138 MMPLAYER_FREEIF(dump_s);
8140 g_list_free(dump_list);
8146 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
8148 mm_player_t* player = (mm_player_t*) hplayer;
8152 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8153 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8155 *exist = player->has_closed_caption;
8159 return MM_ERROR_NONE;
8162 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
8166 // LOGD("unref internal gst buffer %p", buffer);
8167 gst_buffer_unref((GstBuffer *)buffer);
8173 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8175 mm_player_t *player = (mm_player_t *) hplayer;
8179 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8180 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8182 if (MMPLAYER_IS_STREAMING(player))
8183 *timeout = player->ini.live_state_change_timeout;
8185 *timeout = player->ini.localplayback_state_change_timeout;
8187 LOGD("timeout = %d", *timeout);
8190 return MM_ERROR_NONE;
8193 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8195 mm_player_t* player = (mm_player_t*) hplayer;
8199 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8200 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8202 *num = player->video_num_buffers;
8203 *extra_num = player->video_extra_num_buffers;
8205 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8208 return MM_ERROR_NONE;
8212 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
8216 MMPLAYER_RETURN_IF_FAIL(player);
8218 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8220 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8221 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8222 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8223 player->storage_info[i].id = -1;
8224 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8226 if (path_type != MMPLAYER_PATH_MAX)
8234 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8236 int ret = MM_ERROR_NONE;
8237 mm_player_t* player = (mm_player_t*)hplayer;
8238 MMMessageParamType msg_param = {0, };
8241 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8243 LOGW("state changed storage %d:%d", id, state);
8245 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8246 return MM_ERROR_NONE;
8248 /* FIXME: text path should be handled seperately. */
8249 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8250 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8251 LOGW("external storage is removed");
8253 if (player->msg_posted == FALSE) {
8254 memset(&msg_param, 0, sizeof(MMMessageParamType));
8255 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8256 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8257 player->msg_posted = TRUE;
8260 /* unrealize the player */
8261 ret = _mmplayer_unrealize(hplayer);
8262 if (ret != MM_ERROR_NONE)
8263 LOGE("failed to unrealize");
8270 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8272 int ret = MM_ERROR_NONE;
8273 mm_player_t* player = (mm_player_t*) hplayer;
8274 int idx = 0, total = 0;
8275 gchar *result = NULL, *tmp = NULL;
8278 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8279 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8281 total = *num = g_list_length(player->adaptive_info.var_list);
8283 LOGW("There is no stream variant info.");
8287 result = g_strdup("");
8288 for (idx = 0 ; idx < total ; idx++) {
8289 VariantData *v_data = NULL;
8290 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8293 gchar data[64] = {0};
8294 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8296 tmp = g_strconcat(result, data, NULL);
8300 LOGW("There is no variant data in %d", idx);
8305 *var_info = (char *)result;
8307 LOGD("variant info %d:%s", *num, *var_info);
8312 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8314 int ret = MM_ERROR_NONE;
8315 mm_player_t* player = (mm_player_t*) hplayer;
8318 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8320 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8322 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8323 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8324 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8326 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8327 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8328 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8329 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8331 /* FIXME: seek to current position for applying new variant limitation */
8339 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8341 int ret = MM_ERROR_NONE;
8342 mm_player_t* player = (mm_player_t*) hplayer;
8345 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8346 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8348 *bandwidth = player->adaptive_info.limit.bandwidth;
8349 *width = player->adaptive_info.limit.width;
8350 *height = player->adaptive_info.limit.height;
8352 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8358 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
8360 int ret = MM_ERROR_NONE;
8361 mm_player_t* player = (mm_player_t*) hplayer;
8364 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8366 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
8367 LOGW("buffer_ms will not be applied.");
8369 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
8371 if (player->streamer == NULL) {
8372 player->streamer = __mm_player_streaming_create();
8373 __mm_player_streaming_initialize(player->streamer);
8377 player->streamer->buffering_req.prebuffer_time = buffer_ms;
8379 if (rebuffer_ms >= 0)
8380 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
8387 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
8389 int ret = MM_ERROR_NONE;
8390 mm_player_t* player = (mm_player_t*) hplayer;
8393 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8394 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8396 if (player->streamer == NULL) {
8397 player->streamer = __mm_player_streaming_create();
8398 __mm_player_streaming_initialize(player->streamer);
8401 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
8402 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8404 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
8410 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8412 #define IDX_FIRST_SW_CODEC 0
8413 mm_player_t* player = (mm_player_t*) hplayer;
8414 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8415 MMHandleType attrs = 0;
8418 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8420 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8421 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8422 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8424 switch (stream_type) {
8425 case MM_PLAYER_STREAM_TYPE_AUDIO:
8426 /* to support audio codec selection, codec info have to be added in ini file as below.
8427 audio codec element hw = xxxx
8428 audio codec element sw = avdec */
8429 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8430 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8431 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8432 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8433 LOGE("There is no audio codec info for codec_type %d", codec_type);
8434 return MM_ERROR_PLAYER_NO_OP;
8437 case MM_PLAYER_STREAM_TYPE_VIDEO:
8438 /* to support video codec selection, codec info have to be added in ini file as below.
8439 video codec element hw = omx
8440 video codec element sw = avdec */
8441 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8442 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8443 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8444 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8445 LOGE("There is no video codec info for codec_type %d", codec_type);
8446 return MM_ERROR_PLAYER_NO_OP;
8450 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8451 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8455 LOGD("update %s codec_type to %d", attr_name, codec_type);
8457 attrs = MMPLAYER_GET_ATTRS(player);
8458 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8460 if (mm_attrs_commit_all(player->attrs)) {
8461 LOGE("failed to commit codec_type attributes");
8462 return MM_ERROR_PLAYER_INTERNAL;
8466 return MM_ERROR_NONE;
8470 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8472 mm_player_t* player = (mm_player_t*) hplayer;
8473 GstElement* rg_vol_element = NULL;
8477 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8479 player->sound.rg_enable = enabled;
8481 /* just hold rgvolume enable value if pipeline is not ready */
8482 if (!player->pipeline || !player->pipeline->audiobin) {
8483 LOGD("pipeline is not ready. holding rgvolume enable value\n");
8484 return MM_ERROR_NONE;
8487 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8489 if (!rg_vol_element) {
8490 LOGD("rgvolume element is not created");
8491 return MM_ERROR_PLAYER_INTERNAL;
8495 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8497 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8501 return MM_ERROR_NONE;
8505 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8507 mm_player_t* player = (mm_player_t*) hplayer;
8508 GstElement* rg_vol_element = NULL;
8509 gboolean enable = FALSE;
8513 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8514 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8516 /* just hold enable_rg value if pipeline is not ready */
8517 if (!player->pipeline || !player->pipeline->audiobin) {
8518 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
8519 *enabled = player->sound.rg_enable;
8520 return MM_ERROR_NONE;
8523 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8525 if (!rg_vol_element) {
8526 LOGD("rgvolume element is not created");
8527 return MM_ERROR_PLAYER_INTERNAL;
8530 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8535 return MM_ERROR_NONE;
8539 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8541 mm_player_t* player = (mm_player_t*) hplayer;
8542 MMHandleType attrs = 0;
8543 void *handle = NULL;
8544 int ret = MM_ERROR_NONE;
8548 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8550 attrs = MMPLAYER_GET_ATTRS(player);
8551 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8553 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8555 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8556 return MM_ERROR_PLAYER_INTERNAL;
8559 player->video_roi.scale_x = scale_x;
8560 player->video_roi.scale_y = scale_y;
8561 player->video_roi.scale_width = scale_width;
8562 player->video_roi.scale_height = scale_height;
8564 /* check video sinkbin is created */
8565 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8566 return MM_ERROR_NONE;
8568 if (!gst_video_overlay_set_video_roi_area(
8569 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8570 scale_x, scale_y, scale_width, scale_height))
8571 ret = MM_ERROR_PLAYER_INTERNAL;
8573 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8574 scale_x, scale_y, scale_width, scale_height);
8582 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8584 mm_player_t* player = (mm_player_t*) hplayer;
8585 int ret = MM_ERROR_NONE;
8589 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8590 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8592 *scale_x = player->video_roi.scale_x;
8593 *scale_y = player->video_roi.scale_y;
8594 *scale_width = player->video_roi.scale_width;
8595 *scale_height = player->video_roi.scale_height;
8597 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8598 *scale_x, *scale_y, *scale_width, *scale_height);
8604 __mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs)
8606 gboolean ret = FALSE;
8607 gint64 dur_nsec = 0;
8608 LOGD("try to update duration");
8610 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8611 player->duration = dur_nsec;
8612 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8616 if (player->duration < 0) {
8617 LOGW("duration is Non-Initialized !!!");
8618 player->duration = 0;
8621 /* update streaming service type */
8622 player->streaming_type = __mmplayer_get_stream_service_type(player);
8624 /* check duration is OK */
8625 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
8626 /* FIXIT : find another way to get duration here. */
8627 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8634 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8636 /* update audio params
8637 NOTE : We need original audio params and it can be only obtained from src pad of audio
8638 decoder. Below code only valid when we are not using 'resampler' just before
8639 'audioconverter'. */
8640 GstCaps *caps_a = NULL;
8642 gint samplerate = 0, channels = 0;
8643 GstStructure* p = NULL;
8645 LOGD("try to update audio attrs");
8647 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8648 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8650 pad = gst_element_get_static_pad(
8651 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8654 LOGW("failed to get pad from audiosink");
8658 caps_a = gst_pad_get_current_caps(pad);
8661 LOGW("not ready to get audio caps");
8662 gst_object_unref(pad);
8666 p = gst_caps_get_structure(caps_a, 0);
8668 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8670 gst_structure_get_int(p, "rate", &samplerate);
8671 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8673 gst_structure_get_int(p, "channels", &channels);
8674 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8676 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8678 gst_caps_unref(caps_a);
8679 gst_object_unref(pad);
8685 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8687 LOGD("try to update video attrs");
8689 GstCaps *caps_v = NULL;
8693 GstStructure* p = NULL;
8695 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8696 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8698 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8700 LOGD("no videosink sink pad");
8704 caps_v = gst_pad_get_current_caps(pad);
8705 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8706 if (!caps_v && player->v_stream_caps) {
8707 caps_v = player->v_stream_caps;
8708 gst_caps_ref(caps_v);
8712 LOGD("no negitiated caps from videosink");
8713 gst_object_unref(pad);
8717 p = gst_caps_get_structure(caps_v, 0);
8718 gst_structure_get_int(p, "width", &width);
8719 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8721 gst_structure_get_int(p, "height", &height);
8722 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8724 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8726 SECURE_LOGD("width : %d height : %d", width, height);
8728 gst_caps_unref(caps_v);
8729 gst_object_unref(pad);
8732 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8733 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8740 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8742 gboolean ret = FALSE;
8743 guint64 data_size = 0;
8747 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8748 if (!player->duration)
8751 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8752 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8753 if (stat(path, &sb) == 0)
8754 data_size = (guint64)sb.st_size;
8756 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8757 data_size = player->http_content_size;
8760 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8763 guint64 bitrate = 0;
8764 guint64 msec_dur = 0;
8766 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8768 bitrate = data_size * 8 * 1000 / msec_dur;
8769 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8770 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8774 LOGD("player duration is less than 0");
8778 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8779 if (player->total_bitrate) {
8780 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
8788 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile* data, const char *uri, int uri_type)
8790 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8791 data->uri_type = uri_type;
8794 __mmplayer_set_mem_uri(MMPlayerParseProfile* data, char *path, void *param)
8796 int ret = MM_ERROR_PLAYER_INVALID_URI;
8798 char *buffer = NULL;
8799 char *seperator = strchr(path, ',');
8800 char ext[100] = {0,}, size[100] = {0,};
8803 if ((buffer = strstr(path, "ext="))) {
8804 buffer += strlen("ext=");
8806 if (strlen(buffer)) {
8807 strncpy(ext, buffer, 99);
8809 if ((seperator = strchr(ext, ','))
8810 || (seperator = strchr(ext, ' '))
8811 || (seperator = strchr(ext, '\0'))) {
8812 seperator[0] = '\0';
8817 if ((buffer = strstr(path, "size="))) {
8818 buffer += strlen("size=");
8820 if (strlen(buffer) > 0) {
8821 strncpy(size, buffer, 99);
8823 if ((seperator = strchr(size, ','))
8824 || (seperator = strchr(size, ' '))
8825 || (seperator = strchr(size, '\0'))) {
8826 seperator[0] = '\0';
8829 mem_size = atoi(size);
8834 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8836 if (mem_size && param) {
8837 if (data->input_mem.buf)
8838 free(data->input_mem.buf);
8839 data->input_mem.buf = malloc(mem_size);
8841 if (data->input_mem.buf) {
8842 memcpy(data->input_mem.buf, param, mem_size);
8843 data->input_mem.len = mem_size;
8844 ret = MM_ERROR_NONE;
8846 LOGE("failed to alloc mem %d", mem_size);
8847 ret = MM_ERROR_PLAYER_INTERNAL;
8850 data->input_mem.offset = 0;
8851 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8858 __mmplayer_set_file_uri(MMPlayerParseProfile* data, const char *uri)
8860 gchar *location = NULL;
8863 int ret = MM_ERROR_NONE;
8865 if ((path = strstr(uri, "file://"))) {
8866 location = g_filename_from_uri(uri, NULL, &err);
8867 if (!location || (err != NULL)) {
8868 LOGE("Invalid URI '%s' for filesrc: %s", path,
8869 (err != NULL) ? err->message : "unknown error");
8875 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8876 return MM_ERROR_PLAYER_INVALID_URI;
8878 LOGD("path from uri: %s", location);
8881 path = (location != NULL) ? (location) : ((char *)uri);
8884 ret = util_exist_file_path(path);
8886 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8887 if (ret == MM_ERROR_NONE) {
8888 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8889 if (util_is_sdp_file(path)) {
8890 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8891 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8893 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8895 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8896 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8898 LOGE("invalid uri, could not play..\n");
8899 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8908 static MMPlayerVideoStreamDataType*
8909 __mmplayer_create_stream_from_pad(GstPad *pad)
8911 GstCaps *caps = NULL;
8912 GstStructure *structure = NULL;
8913 unsigned int fourcc = 0;
8914 const gchar *string_format = NULL;
8915 MMPlayerVideoStreamDataType *stream = NULL;
8917 MMPixelFormatType format;
8919 caps = gst_pad_get_current_caps(pad);
8921 LOGE("Caps is NULL.");
8925 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
8926 structure = gst_caps_get_structure(caps, 0);
8927 gst_structure_get_int(structure, "width", &width);
8928 gst_structure_get_int(structure, "height", &height);
8929 string_format = gst_structure_get_string(structure, "format");
8931 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
8932 format = util_get_pixtype(fourcc);
8933 gst_caps_unref(caps);
8936 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
8937 LOGE("Wrong condition!!");
8941 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
8943 LOGE("failed to alloc mem for video data");
8947 stream->width = width;
8948 stream->height = height;
8949 stream->format = format;
8955 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
8957 unsigned int pitch = 0;
8959 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
8961 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
8962 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
8963 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
8964 stream->stride[index] = pitch;
8965 stream->elevation[index] = stream->height;
8970 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
8972 if (stream->format == MM_PIXEL_FORMAT_I420) {
8973 int ret = TBM_SURFACE_ERROR_NONE;
8974 tbm_surface_h surface;
8975 tbm_surface_info_s info;
8977 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
8979 ret = tbm_surface_get_info(surface, &info);
8980 if (ret != TBM_SURFACE_ERROR_NONE) {
8981 tbm_surface_destroy(surface);
8985 tbm_surface_destroy(surface);
8986 stream->stride[0] = info.planes[0].stride;
8987 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
8988 stream->stride[1] = info.planes[1].stride;
8989 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
8990 stream->stride[2] = info.planes[2].stride;
8991 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
8992 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
8993 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
8994 stream->stride[0] = stream->width * 4;
8995 stream->elevation[0] = stream->height;
8996 stream->bo_size = stream->stride[0] * stream->height;
8998 LOGE("Not support format %d", stream->format);
9006 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9008 tbm_bo_handle thandle;
9010 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9011 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9012 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9016 unsigned char *src = NULL;
9017 unsigned char *dest = NULL;
9018 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9020 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9022 LOGE("fail to gst_memory_map");
9026 if (!mapinfo.data) {
9027 LOGE("data pointer is wrong");
9031 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9032 if (!stream->bo[0]) {
9033 LOGE("Fail to tbm_bo_alloc!!");
9037 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9039 LOGE("thandle pointer is wrong");
9043 if (stream->format == MM_PIXEL_FORMAT_I420) {
9044 src_stride[0] = GST_ROUND_UP_4(stream->width);
9045 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9046 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9047 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9050 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9051 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9053 for (i = 0; i < 3; i++) {
9054 src = mapinfo.data + src_offset[i];
9055 dest = thandle.ptr + dest_offset[i];
9060 for (j = 0; j < stream->height >> k; j++) {
9061 memcpy(dest, src, stream->width>>k);
9062 src += src_stride[i];
9063 dest += stream->stride[i];
9066 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9067 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9069 LOGE("Not support format %d", stream->format);
9073 tbm_bo_unmap(stream->bo[0]);
9074 gst_memory_unmap(mem, &mapinfo);
9080 tbm_bo_unmap(stream->bo[0]);
9083 gst_memory_unmap(mem, &mapinfo);
9089 __mmplayer_set_pause_state(mm_player_t *player)
9091 if (player->sent_bos)
9094 /* rtsp case, get content attrs by GstMessage */
9095 if (MMPLAYER_IS_RTSP_STREAMING(player))
9098 /* it's first time to update all content attrs. */
9099 __mmplayer_update_content_attrs(player, ATTR_ALL);
9103 __mmplayer_set_playing_state(mm_player_t *player)
9105 gchar *audio_codec = NULL;
9107 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9108 /* initialize because auto resume is done well. */
9109 player->resumed_by_rewind = FALSE;
9110 player->playback_rate = 1.0;
9113 if (player->sent_bos)
9116 /* try to get content metadata */
9118 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9119 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9120 * legacy mmfw-player api
9122 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9124 if ((player->cmd == MMPLAYER_COMMAND_START)
9125 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9126 __mmplayer_handle_missed_plugin(player);
9129 /* check audio codec field is set or not
9130 * we can get it from typefinder or codec's caps.
9132 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9134 /* The codec format can't be sent for audio only case like amr, mid etc.
9135 * Because, parser don't make related TAG.
9136 * So, if it's not set yet, fill it with found data.
9139 if (g_strrstr(player->type, "audio/midi"))
9140 audio_codec = "MIDI";
9141 else if (g_strrstr(player->type, "audio/x-amr"))
9142 audio_codec = "AMR";
9143 else if (g_strrstr(player->type, "audio/mpeg")
9144 && !g_strrstr(player->type, "mpegversion= (int)1"))
9145 audio_codec = "AAC";
9147 audio_codec = "unknown";
9149 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9151 if (mm_attrs_commit_all(player->attrs))
9152 LOGE("failed to update attributes\n");
9154 LOGD("set audio codec type with caps\n");