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>
41 #include <mm_attrs_private.h>
43 #include "mm_player_priv.h"
44 #include "mm_player_ini.h"
45 #include "mm_player_attrs.h"
46 #include "mm_player_capture.h"
47 #include "mm_player_utils.h"
48 #include "mm_player_tracks.h"
49 #include "mm_player_360.h"
50 #include "mm_player_gst.h"
52 #include <system_info.h>
53 #include <sound_manager.h>
54 #include <gst/allocators/gsttizenmemory.h>
55 #include <tbm_surface_internal.h>
57 /*===========================================================================================
59 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
61 ========================================================================================== */
63 /*---------------------------------------------------------------------------
64 | GLOBAL CONSTANT DEFINITIONS: |
65 ---------------------------------------------------------------------------*/
67 /*---------------------------------------------------------------------------
68 | IMPORTED VARIABLE DECLARATIONS: |
69 ---------------------------------------------------------------------------*/
71 /*---------------------------------------------------------------------------
72 | IMPORTED FUNCTION DECLARATIONS: |
73 ---------------------------------------------------------------------------*/
75 /*---------------------------------------------------------------------------
77 ---------------------------------------------------------------------------*/
78 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
79 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
81 #define MM_VOLUME_FACTOR_DEFAULT 1.0
82 #define MM_VOLUME_FACTOR_MIN 0
83 #define MM_VOLUME_FACTOR_MAX 1.0
85 /* Don't need to sleep for sound fadeout
86 * fadeout related fucntion will be deleted(Deprecated)
88 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
90 #define DEFAULT_PLAYBACK_RATE 1.0
91 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
93 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
94 (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
95 (player->ini.http_use_file_buffer) && \
96 (player->http_file_buffering_path) && \
97 (strlen(player->http_file_buffering_path) > 0))
99 #define PLAYER_DISPLAY_MODE_DST_ROI 5
101 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
104 #define PLAYER_PD_EXT_MAX_SIZE_BYTE 1024 * 1024 * 3
105 #define PLAYER_PD_STATE_CHANGE_TIME 20 /* sec */
107 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
108 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
109 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
110 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
112 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
113 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
115 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
117 /*---------------------------------------------------------------------------
118 | LOCAL CONSTANT DEFINITIONS: |
119 ---------------------------------------------------------------------------*/
121 /*---------------------------------------------------------------------------
122 | LOCAL DATA TYPE DEFINITIONS: |
123 ---------------------------------------------------------------------------*/
125 /*---------------------------------------------------------------------------
126 | GLOBAL VARIABLE DEFINITIONS: |
127 ---------------------------------------------------------------------------*/
129 /*---------------------------------------------------------------------------
130 | LOCAL VARIABLE DEFINITIONS: |
131 ---------------------------------------------------------------------------*/
132 static sound_stream_info_h stream_info;
134 /*---------------------------------------------------------------------------
135 | LOCAL FUNCTION PROTOTYPES: |
136 ---------------------------------------------------------------------------*/
137 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
138 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
139 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
140 static int __mmplayer_gst_create_video_sink_bin(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
141 static int __mmplayer_gst_create_audio_sink_bin(mm_player_t* player);
142 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
144 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
145 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
146 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
147 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
148 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
149 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
150 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
151 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
152 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
153 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
154 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
156 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static void __mmplayer_release_misc(mm_player_t* player);
158 static void __mmplayer_release_misc_post(mm_player_t* player);
159 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
160 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
161 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
163 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
165 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
166 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
167 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
168 static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
169 static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
170 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
171 static gpointer __mmplayer_gapless_play_thread(gpointer data);
172 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
173 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static void __mmplayer_release_dump_list(GList *dump_list);
175 static int __mmplayer_gst_realize(mm_player_t* player);
176 static int __mmplayer_gst_unrealize(mm_player_t* player);
177 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
178 static int __mmplayer_gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
181 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
182 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
183 static int __mmplayer_start_streaming_ext(mm_player_t *player);
184 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
185 static gboolean __mmplayer_verify_gapless_play_path(mm_player_t *player);
186 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
187 static void __mmplayer_check_pipeline(mm_player_t* player);
188 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
189 static void __mmplayer_deactivate_old_path(mm_player_t *player);
190 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
191 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
192 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
193 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
194 static void __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
195 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
196 static gboolean __mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs);
197 static gboolean __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs);
198 static gboolean __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs);
199 static gboolean __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs);
201 static void __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile* data, const char *uri, int uri_type);
202 static int __mmplayer_set_mem_uri(MMPlayerParseProfile* data, char *path, void *param);
203 static int __mmplayer_set_file_uri(MMPlayerParseProfile* data, const char *uri);
205 static MMPlayerVideoStreamDataType* __mmplayer_create_stream_from_pad(GstPad *pad);
206 static void __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem);
207 static gboolean __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream);
208 static gboolean __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem);
209 /*===========================================================================================
211 | FUNCTION DEFINITIONS |
213 ========================================================================================== */
217 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
221 count = gst_tag_list_get_tag_size(list, tag);
223 LOGD("count = %d", count);
225 for (i = 0; i < count; i++) {
228 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
229 if (!gst_tag_list_get_string_index(list, tag, i, &str))
230 g_assert_not_reached();
232 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
235 g_print(" %15s: %s\n", gst_tag_get_nick(tag), str);
237 g_print(" : %s\n", str);
244 /* This function should be called after the pipeline goes PAUSED or higher
247 __mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
249 static gboolean has_duration = FALSE;
250 static gboolean has_video_attrs = FALSE;
251 static gboolean has_audio_attrs = FALSE;
252 static gboolean has_bitrate = FALSE;
253 gboolean missing_only = FALSE;
254 gboolean all = FALSE;
255 MMHandleType attrs = 0;
259 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
261 /* check player state here */
262 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
263 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
264 /* give warning now only */
265 LOGW("be careful. content attributes may not available in this state ");
268 /* get content attribute first */
269 attrs = MMPLAYER_GET_ATTRS(player);
271 LOGE("cannot get content attribute");
275 /* get update flag */
277 if (flag & ATTR_MISSING_ONLY) {
279 LOGD("updating missed attr only");
282 if (flag & ATTR_ALL) {
284 has_duration = FALSE;
285 has_video_attrs = FALSE;
286 has_audio_attrs = FALSE;
289 LOGD("updating all attrs");
292 if (missing_only && all) {
293 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
294 missing_only = FALSE;
297 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
298 has_duration = __mmplayer_update_duration_attrs(player, attrs);
300 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
301 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
303 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
304 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
306 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
307 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
310 if (mmf_attrs_commit(attrs)) {
311 LOGE("failed to update attributes\n");
320 MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
322 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
326 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
328 player->pipeline->mainbin &&
329 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
330 STREAMING_SERVICE_NONE);
332 /* streaming service type if streaming */
333 if (!MMPLAYER_IS_STREAMING(player))
334 return STREAMING_SERVICE_NONE;
336 streaming_type = (player->duration == 0) ?
337 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
339 switch (streaming_type) {
340 case STREAMING_SERVICE_LIVE:
341 LOGD("it's live streaming");
343 case STREAMING_SERVICE_VOD:
344 LOGD("it's vod streaming");
347 LOGE("should not get here");
353 return streaming_type;
357 /* this function sets the player state and also report
358 * it to applicaton by calling callback function
361 __mmplayer_set_state(mm_player_t* player, int state)
363 MMMessageParamType msg = {0, };
364 gboolean post_bos = FALSE;
366 MMPLAYER_RETURN_IF_FAIL(player);
368 if (MMPLAYER_CURRENT_STATE(player) == state) {
369 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
370 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
374 /* update player states */
375 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
376 MMPLAYER_CURRENT_STATE(player) = state;
378 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
379 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
382 MMPLAYER_PRINT_STATE(player);
384 switch (MMPLAYER_CURRENT_STATE(player)) {
385 case MM_PLAYER_STATE_NULL:
386 case MM_PLAYER_STATE_READY:
389 case MM_PLAYER_STATE_PAUSED:
391 if (!player->sent_bos) {
392 /* rtsp case, get content attrs by GstMessage */
393 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
394 /* it's first time to update all content attrs. */
395 __mmplayer_update_content_attrs(player, ATTR_ALL);
401 case MM_PLAYER_STATE_PLAYING:
403 /* try to get content metadata */
404 if (!player->sent_bos) {
405 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
406 * c-api since c-api doesn't use _start() anymore. It may not work propery with
407 * legacy mmfw-player api */
408 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
411 if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
412 if (!player->sent_bos)
413 __mmplayer_handle_missed_plugin(player);
416 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
417 /* initialize because auto resume is done well. */
418 player->resumed_by_rewind = FALSE;
419 player->playback_rate = 1.0;
422 if (!player->sent_bos) {
423 /* check audio codec field is set or not
424 * we can get it from typefinder or codec's caps.
426 gchar *audio_codec = NULL;
427 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
429 /* The codec format can't be sent for audio only case like amr, mid etc.
430 * Because, parser don't make related TAG.
431 * So, if it's not set yet, fill it with found data.
434 if (g_strrstr(player->type, "audio/midi"))
435 audio_codec = g_strdup("MIDI");
436 else if (g_strrstr(player->type, "audio/x-amr"))
437 audio_codec = g_strdup("AMR");
438 else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
439 audio_codec = g_strdup("AAC");
441 audio_codec = g_strdup("unknown");
442 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
444 MMPLAYER_FREEIF(audio_codec);
445 if (mmf_attrs_commit(player->attrs))
446 LOGE("failed to update attributes\n");
448 LOGD("set audio codec type with caps\n");
456 case MM_PLAYER_STATE_NONE:
458 LOGW("invalid target state, there is nothing to do.\n");
463 /* post message to application */
464 if (MMPLAYER_TARGET_STATE(player) == state) {
465 /* fill the message with state of player */
466 msg.union_type = MM_MSG_UNION_STATE;
467 msg.state.previous = MMPLAYER_PREV_STATE(player);
468 msg.state.current = MMPLAYER_CURRENT_STATE(player);
470 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
472 /* state changed by resource callback */
473 if (player->interrupted_by_resource) {
474 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
475 } else { /* state changed by usecase */
476 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
479 LOGD("intermediate state, do nothing.\n");
480 MMPLAYER_PRINT_STATE(player);
485 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
486 player->sent_bos = TRUE;
493 __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command)
495 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
496 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
498 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
500 //LOGD("incomming command : %d \n", command);
502 current_state = MMPLAYER_CURRENT_STATE(player);
503 pending_state = MMPLAYER_PENDING_STATE(player);
505 MMPLAYER_PRINT_STATE(player);
508 case MMPLAYER_COMMAND_CREATE:
510 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
512 if (current_state == MM_PLAYER_STATE_NULL ||
513 current_state == MM_PLAYER_STATE_READY ||
514 current_state == MM_PLAYER_STATE_PAUSED ||
515 current_state == MM_PLAYER_STATE_PLAYING)
520 case MMPLAYER_COMMAND_DESTROY:
522 /* destroy can called anytime */
524 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
528 case MMPLAYER_COMMAND_REALIZE:
530 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
532 if (pending_state != MM_PLAYER_STATE_NONE) {
535 /* need ready state to realize */
536 if (current_state == MM_PLAYER_STATE_READY)
539 if (current_state != MM_PLAYER_STATE_NULL)
545 case MMPLAYER_COMMAND_UNREALIZE:
547 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
549 if (current_state == MM_PLAYER_STATE_NULL)
554 case MMPLAYER_COMMAND_START:
556 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
558 if (pending_state == MM_PLAYER_STATE_NONE) {
559 if (current_state == MM_PLAYER_STATE_PLAYING)
561 else if (current_state != MM_PLAYER_STATE_READY &&
562 current_state != MM_PLAYER_STATE_PAUSED)
564 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
566 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
567 LOGD("player is going to paused state, just change the pending state as playing");
573 case MMPLAYER_COMMAND_STOP:
575 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
577 if (current_state == MM_PLAYER_STATE_READY)
580 /* need playing/paused state to stop */
581 if (current_state != MM_PLAYER_STATE_PLAYING &&
582 current_state != MM_PLAYER_STATE_PAUSED)
587 case MMPLAYER_COMMAND_PAUSE:
589 if (MMPLAYER_IS_LIVE_STREAMING(player))
592 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
593 goto NOT_COMPLETED_SEEK;
595 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
597 if (pending_state == MM_PLAYER_STATE_NONE) {
598 if (current_state == MM_PLAYER_STATE_PAUSED)
600 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
602 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
604 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
605 if (current_state == MM_PLAYER_STATE_PAUSED)
606 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
613 case MMPLAYER_COMMAND_RESUME:
615 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
616 goto NOT_COMPLETED_SEEK;
618 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
620 if (pending_state == MM_PLAYER_STATE_NONE) {
621 if (current_state == MM_PLAYER_STATE_PLAYING)
623 else if (current_state != MM_PLAYER_STATE_PAUSED)
625 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
627 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
628 LOGD("player is going to paused state, just change the pending state as playing");
637 player->cmd = command;
639 return MM_ERROR_NONE;
642 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
643 MMPLAYER_STATE_GET_NAME(current_state), command);
644 return MM_ERROR_PLAYER_INVALID_STATE;
647 LOGW("not completed seek");
648 return MM_ERROR_PLAYER_DOING_SEEK;
651 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
652 return MM_ERROR_PLAYER_NO_OP;
655 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
656 return MM_ERROR_PLAYER_NO_OP;
659 static gpointer __mmplayer_gapless_play_thread(gpointer data)
661 mm_player_t* player = (mm_player_t*) data;
662 MMPlayerGstElement *mainbin = NULL;
664 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
666 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
667 while (!player->gapless_play_thread_exit) {
668 LOGD("gapless play thread started. waiting for signal.\n");
669 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
671 LOGD("reconfigure pipeline for gapless play.\n");
673 if (player->gapless_play_thread_exit) {
674 if (player->gapless.reconfigure) {
675 player->gapless.reconfigure = false;
676 MMPLAYER_PLAYBACK_UNLOCK(player);
678 LOGD("exiting gapless play thread\n");
682 mainbin = player->pipeline->mainbin;
684 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
685 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
686 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
687 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
688 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
690 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
692 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
698 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
700 GSource *source = NULL;
704 source = g_main_context_find_source_by_id(context, source_id);
706 if (source != NULL) {
707 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
708 g_source_destroy(source);
714 void __mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
716 mm_player_t* player = (mm_player_t*)hplayer;
717 GstMessage *msg = NULL;
718 GQueue *queue = NULL;
721 MMPLAYER_RETURN_IF_FAIL(player);
723 /* disconnecting bus watch */
724 if (player->bus_watcher)
725 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
726 player->bus_watcher = 0;
728 /* destroy the gst bus msg thread */
729 if (player->bus_msg_thread) {
730 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
731 player->bus_msg_thread_exit = TRUE;
732 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
733 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
735 LOGD("gst bus msg thread exit.");
736 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
737 player->bus_msg_thread = NULL;
739 g_mutex_clear(&player->bus_msg_thread_mutex);
740 g_cond_clear(&player->bus_msg_thread_cond);
743 g_mutex_lock(&player->bus_msg_q_lock);
744 queue = player->bus_msg_q;
745 while (!g_queue_is_empty(queue)) {
746 msg = (GstMessage *)g_queue_pop_head(queue);
751 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
752 gst_message_unref(msg);
754 g_mutex_unlock(&player->bus_msg_q_lock);
760 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
762 GstElement* parent = NULL;
764 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
766 /* if we have no fakesink. this meas we are using decodebin which doesn'
767 t need to add extra fakesink */
768 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
771 MMPLAYER_FSINK_LOCK(player);
776 /* get parent of fakesink */
777 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
779 LOGD("fakesink already removed\n");
783 gst_element_set_locked_state(fakesink->gst, TRUE);
785 /* setting the state to NULL never returns async
786 * so no need to wait for completion of state transiton
788 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
789 LOGE("fakesink state change failure!\n");
790 /* FIXIT : should I return here? or try to proceed to next? */
793 /* remove fakesink from it's parent */
794 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
795 LOGE("failed to remove fakesink\n");
797 gst_object_unref(parent);
802 gst_object_unref(parent);
804 LOGD("state-holder removed\n");
806 gst_element_set_locked_state(fakesink->gst, FALSE);
808 MMPLAYER_FSINK_UNLOCK(player);
813 gst_element_set_locked_state(fakesink->gst, FALSE);
815 MMPLAYER_FSINK_UNLOCK(player);
819 static GstPadProbeReturn
820 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
822 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
823 return GST_PAD_PROBE_OK;
827 __mmplayer_gst_selector_update_start_time(mm_player_t* player, MMPlayerTrackType stream_type)
829 gint64 stop_running_time = 0;
830 gint64 position_running_time = 0;
834 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
835 if ((player->gapless.update_segment[idx] == TRUE) ||
836 !(player->selector[idx].event_probe_id)) {
837 /* LOGW("[%d] skip", idx); */
841 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
843 gst_segment_to_running_time(&player->gapless.segment[idx],
844 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
845 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
847 gst_segment_to_running_time(&player->gapless.segment[idx],
848 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
850 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
852 gst_segment_to_running_time(&player->gapless.segment[idx],
853 GST_FORMAT_TIME, player->duration);
856 position_running_time =
857 gst_segment_to_running_time(&player->gapless.segment[idx],
858 GST_FORMAT_TIME, player->gapless.segment[idx].position);
860 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
861 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
863 GST_TIME_ARGS(stop_running_time),
864 GST_TIME_ARGS(position_running_time),
865 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
866 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
868 position_running_time = MAX(position_running_time, stop_running_time);
869 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
870 GST_FORMAT_TIME, player->gapless.segment[idx].start);
871 position_running_time = MAX(0, position_running_time);
872 position = MAX(position, position_running_time);
876 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
877 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
878 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
880 player->gapless.start_time[stream_type] += position;
886 static GstPadProbeReturn
887 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
889 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
890 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
891 mm_player_t *player = (mm_player_t*)data;
892 GstCaps *caps = NULL;
893 GstStructure *str = NULL;
894 const gchar *name = NULL;
895 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
896 gboolean caps_ret = TRUE;
898 if (GST_EVENT_IS_DOWNSTREAM(event) &&
899 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
900 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
901 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
902 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
904 } else if (GST_EVENT_IS_UPSTREAM(event) &&
905 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
909 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
913 if (strstr(name, "audio")) {
914 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
915 } else if (strstr(name, "video")) {
916 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
918 /* text track is not supportable */
919 LOGE("invalid name %s", name);
923 switch (GST_EVENT_TYPE(event)) {
926 /* in case of gapless, drop eos event not to send it to sink */
927 if (player->gapless.reconfigure && !player->msg_posted) {
928 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
929 ret = GST_PAD_PROBE_DROP;
933 case GST_EVENT_STREAM_START:
935 __mmplayer_gst_selector_update_start_time(player, stream_type);
938 case GST_EVENT_FLUSH_STOP:
940 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
941 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
942 player->gapless.start_time[stream_type] = 0;
945 case GST_EVENT_SEGMENT:
950 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
951 gst_event_copy_segment(event, &segment);
953 if (segment.format != GST_FORMAT_TIME)
956 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
957 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
958 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
959 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
960 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
961 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
963 /* keep the all the segment ev to cover the seeking */
964 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
965 player->gapless.update_segment[stream_type] = TRUE;
967 if (!player->gapless.running)
970 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
972 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
974 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
975 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
976 gst_event_unref(event);
977 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
983 gdouble proportion = 0.0;
984 GstClockTimeDiff diff = 0;
985 GstClockTime timestamp = 0;
986 gint64 running_time_diff = -1;
988 GstEvent *tmpev = NULL;
990 running_time_diff = player->gapless.segment[stream_type].base;
992 if (running_time_diff <= 0) /* don't need to adjust */
995 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
996 gst_event_unref(event);
998 if (timestamp < running_time_diff) {
999 LOGW("QOS event from previous group");
1000 ret = GST_PAD_PROBE_DROP;
1004 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1005 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1006 stream_type, GST_TIME_ARGS(timestamp),
1007 GST_TIME_ARGS(running_time_diff),
1008 GST_TIME_ARGS(timestamp - running_time_diff));
1010 timestamp -= running_time_diff;
1012 /* That case is invalid for QoS events */
1013 if (diff < 0 && -diff > timestamp) {
1014 LOGW("QOS event from previous group");
1015 ret = GST_PAD_PROBE_DROP;
1019 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1020 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1030 gst_caps_unref(caps);
1034 /* create fakesink for audio or video path witout audiobin or videobin */
1036 __mmplayer_gst_make_fakesink(mm_player_t *player, GstPad *pad, const gchar *name)
1038 GstElement *pipeline = NULL;
1039 GstElement *fakesink = NULL;
1040 GstPad *sinkpad = NULL;
1043 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1045 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1048 fakesink = gst_element_factory_make("fakesink", NULL);
1049 if (fakesink == NULL) {
1050 LOGE("failed to create fakesink");
1054 /* store it as it's sink element */
1055 __mmplayer_add_sink(player, fakesink);
1057 gst_bin_add(GST_BIN(pipeline), fakesink);
1060 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1062 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1064 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1065 LOGE("failed to link fakesink");
1066 gst_object_unref(GST_OBJECT(fakesink));
1070 if (strstr(name, "video")) {
1071 player->video_fakesink = fakesink;
1073 if (player->v_stream_caps) {
1074 gst_caps_unref(player->v_stream_caps);
1075 player->v_stream_caps = NULL;
1078 if (player->ini.set_dump_element_flag)
1079 __mmplayer_add_dump_buffer_probe(player, fakesink);
1082 if (player->set_mode.media_packet_video_stream) { /* export video decoded frame */
1083 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
1085 __mmplayer_add_signal_connection(player,
1087 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
1089 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
1092 __mmplayer_add_signal_connection(player,
1094 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
1096 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
1101 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1102 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1106 gst_object_unref(GST_OBJECT(sinkpad));
1113 __mmplayer_gst_make_selector(mm_player_t *player, enum MainElementID elem_idx, MMPlayerTrackType stream_type)
1115 GstElement *pipeline = NULL;
1116 GstElement *selector = NULL;
1117 GstPad *srcpad = NULL;
1120 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1122 selector = gst_element_factory_make("input-selector", NULL);
1124 LOGE("failed to create input-selector");
1127 g_object_set(selector, "sync-streams", TRUE, NULL);
1129 player->pipeline->mainbin[elem_idx].id = elem_idx;
1130 player->pipeline->mainbin[elem_idx].gst = selector;
1132 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1134 srcpad = gst_element_get_static_pad(selector, "src");
1136 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1137 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1138 __mmplayer_gst_selector_blocked, NULL, NULL);
1139 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1140 __mmplayer_gst_selector_event_probe, player, NULL);
1142 gst_element_set_state(selector, GST_STATE_PAUSED);
1144 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1145 gst_bin_add(GST_BIN(pipeline), selector);
1152 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1154 mm_player_t *player = NULL;
1155 GstElement *selector = NULL;
1156 GstCaps *caps = NULL;
1157 GstStructure *str = NULL;
1158 const gchar *name = NULL;
1159 GstPad *sinkpad = NULL;
1160 GstPad *srcpad = NULL;
1161 gboolean first_track = FALSE;
1162 gboolean caps_ret = TRUE;
1164 enum MainElementID elem_idx = MMPLAYER_M_NUM;
1165 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1168 player = (mm_player_t*)data;
1171 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1172 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1174 LOGD("pad-added signal handling");
1176 /* get mimetype from caps */
1177 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1181 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1182 /* LOGD("detected mimetype : %s", name); */
1184 if (strstr(name, "video")) {
1186 gchar *caps_str = NULL;
1188 caps_str = gst_caps_to_string(caps);
1189 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1190 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1191 player->set_mode.video_zc = TRUE;
1193 MMPLAYER_FREEIF(caps_str);
1195 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1196 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1198 LOGD("surface type : %d", stype);
1200 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1201 __mmplayer_gst_create_sinkbin(elem, pad, player);
1205 if (stype == MM_DISPLAY_SURFACE_NULL) {
1206 __mmplayer_gst_make_fakesink(player, pad, name);
1210 LOGD("video selector is required");
1211 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1212 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1213 } else if (strstr(name, "audio")) {
1214 gint samplerate = 0;
1217 gst_structure_get_int(str, "rate", &samplerate);
1218 gst_structure_get_int(str, "channels", &channels);
1220 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1221 __mmplayer_gst_create_sinkbin(elem, pad, player);
1225 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1226 __mmplayer_gst_make_fakesink(player, pad, name);
1230 LOGD("audio selector is required");
1231 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1232 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1234 } else if (strstr(name, "text")) {
1235 LOGD("text selector is required");
1236 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1237 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1239 LOGE("invalid caps info");
1243 /* check selector and create it */
1244 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1245 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1250 LOGD("input-selector is already created.");
1254 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1256 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1258 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1259 LOGE("failed to link selector");
1260 gst_object_unref(GST_OBJECT(selector));
1265 LOGD("this track will be activated");
1266 g_object_set(selector, "active-pad", sinkpad, NULL);
1269 __mmplayer_track_update_info(player, stream_type, sinkpad);
1275 gst_caps_unref(caps);
1278 gst_object_unref(GST_OBJECT(sinkpad));
1283 gst_object_unref(GST_OBJECT(srcpad));
1290 static gboolean __mmplayer_create_sink_path(mm_player_t* player, GstElement* selector, MMPlayerTrackType type)
1292 GstPad* srcpad = NULL;
1295 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1297 LOGD("type %d", type);
1300 LOGD("there is no %d track", type);
1304 srcpad = gst_element_get_static_pad(selector, "src");
1306 LOGE("failed to get srcpad from selector");
1310 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1312 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1314 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1315 if (player->selector[type].block_id) {
1316 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1317 player->selector[type].block_id = 0;
1321 gst_object_unref(GST_OBJECT(srcpad));
1329 static void __mmplayer_set_decode_track_info(mm_player_t* player, MMPlayerTrackType type)
1331 MMHandleType attrs = 0;
1332 gint active_index = 0;
1333 gchar *attr_name = NULL;
1336 MMPLAYER_RETURN_IF_FAIL(player);
1338 LOGD("type %d", type);
1340 /* change track to active pad */
1341 active_index = player->selector[type].active_pad_index;
1342 if ((active_index != DEFAULT_TRACK) &&
1343 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1344 LOGW("failed to change %d type track to %d", type, active_index);
1345 player->selector[type].active_pad_index = DEFAULT_TRACK;
1348 LOGD("Total num of tracks = %d", player->selector[type].total_track_num);
1350 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
1351 attr_name = "content_audio_track_num";
1352 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1353 attr_name = "content_text_track_num";
1355 LOGE("invalid type info %d", type);
1359 attrs = MMPLAYER_GET_ATTRS(player);
1361 mm_attrs_set_int_by_name(attrs, attr_name, (gint)player->selector[type].total_track_num);
1362 if (mmf_attrs_commit(attrs))
1363 LOGW("failed to commit attrs.");
1365 LOGW("cannot get content attribute");
1372 static gboolean __mmplayer_create_audio_sink_path(mm_player_t* player, GstElement* audio_selector)
1375 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1377 if (!audio_selector) {
1378 LOGD("there is no audio track");
1380 /* in case the source is changed, output can be changed. */
1381 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1382 LOGD("remove previous audiobin if it exist");
1384 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1385 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1387 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1388 MMPLAYER_FREEIF(player->pipeline->audiobin);
1391 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1392 __mmplayer_pipeline_complete(NULL, player);
1397 /* apply the audio track information */
1398 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1400 /* create audio sink path */
1401 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1402 LOGE("failed to create audio sink path");
1410 static gboolean __mmplayer_create_text_sink_path(mm_player_t* player, GstElement* text_selector)
1413 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1415 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1416 LOGD("text path is not supproted");
1420 /* apply the text track information */
1421 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1423 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1424 player->has_closed_caption = TRUE;
1426 /* create text decode path */
1427 player->no_more_pad = TRUE;
1429 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1430 LOGE("failed to create text sink path");
1439 __mmplayer_gst_set_queue2_buffering(mm_player_t *player)
1441 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
1443 gint init_buffering_time = 0;
1444 guint buffer_bytes = 0;
1445 gint64 dur_bytes = 0L;
1448 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1449 player->pipeline->mainbin && player->streamer, FALSE);
1451 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
1452 buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
1454 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
1455 LOGD("pre buffer time: %d ms, buffer size : %d", init_buffering_time, buffer_bytes);
1457 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
1459 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1460 LOGE("fail to get duration.");
1462 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1463 * use file information was already set on Q2 when it was created. */
1464 __mm_player_streaming_set_queue2(player->streamer,
1465 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1466 TRUE, /* use_buffering */
1468 init_buffering_time,
1469 1.0, /* low percent */
1470 player->ini.http_buffering_limit, /* high percent */
1471 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1473 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1480 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1482 mm_player_t *player = NULL;
1483 GstElement *video_selector = NULL;
1484 GstElement *audio_selector = NULL;
1485 GstElement *text_selector = NULL;
1488 player = (mm_player_t*) data;
1490 LOGD("no-more-pad signal handling");
1492 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1493 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1494 LOGW("player is shutting down");
1498 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
1499 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
1500 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1501 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1502 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1503 LOGE("failed to set queue2 buffering");
1508 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1509 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1510 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1512 /* create video path followed by video-select */
1513 if (video_selector && !audio_selector && !text_selector)
1514 player->no_more_pad = TRUE;
1516 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1519 /* create audio path followed by audio-select */
1520 if (audio_selector && !text_selector)
1521 player->no_more_pad = TRUE;
1523 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1527 /* create text path followed by text-select */
1528 __mmplayer_create_text_sink_path(player, text_selector);
1531 if (player->gapless.reconfigure) {
1532 player->gapless.reconfigure = FALSE;
1533 MMPLAYER_PLAYBACK_UNLOCK(player);
1540 __mmplayer_gst_add_sinkbin_to_pipeline(mm_player_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1542 gboolean ret = FALSE;
1543 GstElement *pipeline = NULL;
1544 GstPad *sinkpad = NULL;
1547 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1548 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1550 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1552 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1554 LOGE("failed to get pad from sinkbin");
1560 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1561 LOGE("failed to link sinkbin for reusing");
1562 goto EXIT; /* exit either pass or fail */
1566 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1567 LOGE("failed to set state(READY) to sinkbin");
1572 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1573 LOGE("failed to add sinkbin to pipeline");
1578 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1579 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1584 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1585 LOGE("failed to set state(PAUSED) to sinkbin");
1594 gst_object_unref(GST_OBJECT(sinkpad));
1601 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1603 mm_player_t *player = NULL;
1604 MMHandleType attrs = 0;
1605 GstCaps *caps = NULL;
1606 gchar *caps_str = NULL;
1607 GstStructure *str = NULL;
1608 const gchar *name = NULL;
1609 GstElement *sinkbin = NULL;
1610 gboolean reusing = FALSE;
1611 gboolean caps_ret = TRUE;
1612 gchar *sink_pad_name = "sink";
1615 player = (mm_player_t*) data;
1618 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1619 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1621 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1625 caps_str = gst_caps_to_string(caps);
1627 /* LOGD("detected mimetype : %s", name); */
1628 if (strstr(name, "audio")) {
1629 if (player->pipeline->audiobin == NULL) {
1630 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1631 LOGE("failed to create audiobin. continuing without audio");
1635 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1636 LOGD("creating audiobin success");
1639 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1640 LOGD("reusing audiobin");
1641 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
1643 } else if (strstr(name, "video")) {
1644 /* 1. zero copy is updated at _decode_pad_added()
1645 * 2. NULL surface type is handled in _decode_pad_added() */
1646 LOGD("zero copy %d", player->set_mode.video_zc);
1647 if (player->pipeline->videobin == NULL) {
1648 int surface_type = 0;
1649 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1650 LOGD("display_surface_type (%d)", surface_type);
1652 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) {
1653 LOGD("mark video overlay for acquire");
1654 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1655 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1656 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1657 &player->video_overlay_resource)
1658 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1659 LOGE("could not mark video_overlay resource for acquire");
1664 player->interrupted_by_resource = FALSE;
1666 if (mm_resource_manager_commit(player->resource_manager) !=
1667 MM_RESOURCE_MANAGER_ERROR_NONE) {
1668 LOGE("could not acquire resources for video playing");
1672 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1673 LOGE("failed to create videobin. continuing without video");
1677 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1678 LOGD("creating videosink bin success");
1681 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1682 LOGD("re-using videobin");
1683 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
1685 } else if (strstr(name, "text")) {
1686 if (player->pipeline->textbin == NULL) {
1687 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1688 LOGE("failed to create text sink bin. continuing without text");
1692 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1693 LOGD("creating textsink bin success");
1695 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
1696 player->textsink_linked = 1;
1699 if (!player->textsink_linked) {
1700 LOGD("re-using textbin");
1702 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1703 player->textsink_linked = 1;
1705 /* linked textbin exist which means that the external subtitle path exist already */
1706 LOGW("ignoring internal subtutle since external subtitle is available");
1709 sink_pad_name = "text_sink";
1711 LOGW("unknown mime type %s, ignoring it", name);
1715 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1718 LOGD("[handle: %p] success to create and link sink bin", player);
1720 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1721 * streaming task. if the task blocked, then buffer will not flow to the next element
1722 *(autoplugging element). so this is special hack for streaming. please try to remove it
1724 /* dec stream count. we can remove fakesink if it's zero */
1725 if (player->num_dynamic_pad)
1726 player->num_dynamic_pad--;
1728 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1730 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1731 __mmplayer_pipeline_complete(NULL, player);
1735 MMPLAYER_FREEIF(caps_str);
1738 gst_caps_unref(caps);
1740 /* flusing out new attributes */
1741 if (mmf_attrs_commit(attrs))
1742 LOGE("failed to comit attributes");
1748 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int display_angle, int orientation, int *value)
1750 int required_angle = 0; /* Angle required for straight view */
1751 int rotation_angle = 0;
1753 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1754 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1756 /* Counter clockwise */
1757 switch (orientation) {
1762 required_angle = 270;
1765 required_angle = 180;
1768 required_angle = 90;
1772 rotation_angle = display_angle + required_angle;
1773 if (rotation_angle >= 360)
1774 rotation_angle -= 360;
1776 /* chech if supported or not */
1777 if (rotation_angle % 90) {
1778 LOGD("not supported rotation angle = %d", rotation_angle);
1782 switch (rotation_angle) {
1784 *value = MM_DISPLAY_ROTATION_NONE;
1787 *value = MM_DISPLAY_ROTATION_90;
1790 *value = MM_DISPLAY_ROTATION_180;
1793 *value = MM_DISPLAY_ROTATION_270;
1797 LOGD("setting rotation property value : %d", value);
1803 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
1805 /* check video sinkbin is created */
1806 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1808 player->pipeline->videobin &&
1809 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1810 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1811 MM_ERROR_PLAYER_NOT_INITIALIZED);
1813 return MM_ERROR_NONE;
1817 __mmplayer_get_video_angle(mm_player_t* player, int *display_angle, int *orientation)
1819 int display_rotation = 0;
1820 gchar *org_orient = NULL;
1821 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1824 LOGE("cannot get content attribute");
1825 return MM_ERROR_PLAYER_INTERNAL;
1828 if (display_angle) {
1829 /* update user roation */
1830 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1832 /* Counter clockwise */
1833 switch (display_rotation) {
1834 case MM_DISPLAY_ROTATION_NONE:
1837 case MM_DISPLAY_ROTATION_90:
1838 *display_angle = 90;
1840 case MM_DISPLAY_ROTATION_180:
1841 *display_angle = 180;
1843 case MM_DISPLAY_ROTATION_270:
1844 *display_angle = 270;
1847 LOGW("wrong angle type : %d", display_rotation);
1850 LOGD("check user angle: %d", *display_angle);
1854 /* Counter clockwise */
1855 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1858 if (!strcmp(org_orient, "rotate-90"))
1860 else if (!strcmp(org_orient, "rotate-180"))
1862 else if (!strcmp(org_orient, "rotate-270"))
1865 LOGD("original rotation is %s", org_orient);
1867 LOGD("content_video_orientation get fail");
1870 LOGD("check orientation: %d", *orientation);
1873 return MM_ERROR_NONE;
1877 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
1879 int rotation_value = 0;
1880 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1881 int display_angle = 0;
1884 /* check video sinkbin is created */
1885 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1888 __mmplayer_get_video_angle(player, &display_angle, &orientations);
1890 /* get rotation value to set */
1891 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1892 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1893 LOGD("set video param : rotate %d", rotation_value);
1897 __mmplayer_video_param_set_display_visible(mm_player_t* player)
1899 MMHandleType attrs = 0;
1903 /* check video sinkbin is created */
1904 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1907 attrs = MMPLAYER_GET_ATTRS(player);
1908 MMPLAYER_RETURN_IF_FAIL(attrs);
1910 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1911 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1912 LOGD("set video param : visible %d", visible);
1916 __mmplayer_video_param_set_display_method(mm_player_t* player)
1918 MMHandleType attrs = 0;
1919 int display_method = 0;
1922 /* check video sinkbin is created */
1923 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1926 attrs = MMPLAYER_GET_ATTRS(player);
1927 MMPLAYER_RETURN_IF_FAIL(attrs);
1929 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1930 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1931 LOGD("set video param : method %d", display_method);
1934 __mmplayer_video_param_set_video_roi_area(mm_player_t* player)
1936 MMHandleType attrs = 0;
1937 void *handle = NULL;
1940 /* check video sinkbin is created */
1941 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1942 LOGW("There is no video sink");
1946 attrs = MMPLAYER_GET_ATTRS(player);
1947 MMPLAYER_RETURN_IF_FAIL(attrs);
1948 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1950 gst_video_overlay_set_video_roi_area(
1951 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1952 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1953 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1954 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1959 __mmplayer_video_param_set_roi_area(mm_player_t* player)
1961 MMHandleType attrs = 0;
1962 void *handle = NULL;
1966 int win_roi_width = 0;
1967 int win_roi_height = 0;
1970 /* check video sinkbin is created */
1971 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1972 LOGW("There is no video sink");
1976 attrs = MMPLAYER_GET_ATTRS(player);
1977 MMPLAYER_RETURN_IF_FAIL(attrs);
1979 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1982 /* It should be set after setting window */
1983 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1984 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1985 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1986 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1988 /* After setting window handle, set display roi area */
1989 gst_video_overlay_set_display_roi_area(
1990 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1991 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1992 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1993 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1997 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
1999 MMHandleType attrs = 0;
2000 void *handle = NULL;
2002 /* check video sinkbin is created */
2003 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2006 attrs = MMPLAYER_GET_ATTRS(player);
2007 MMPLAYER_RETURN_IF_FAIL(attrs);
2009 /* common case if using overlay surface */
2010 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2013 /* default is using wl_surface_id */
2014 unsigned int wl_surface_id = 0;
2015 wl_surface_id = *(int*)handle;
2016 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
2017 gst_video_overlay_set_wl_window_wl_surface_id(
2018 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2021 /* FIXIT : is it error case? */
2022 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
2027 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
2029 bool update_all_param = FALSE;
2032 /* check video sinkbin is created */
2033 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2034 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2036 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2037 LOGE("can not find tizenwlsink");
2038 return MM_ERROR_PLAYER_INTERNAL;
2041 LOGD("param_name : %s", param_name);
2042 if (!g_strcmp0(param_name, "update_all_param"))
2043 update_all_param = TRUE;
2045 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2046 __mmplayer_video_param_set_display_overlay(player);
2047 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2048 __mmplayer_video_param_set_display_method(player);
2049 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2050 __mmplayer_video_param_set_display_visible(player);
2051 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2052 __mmplayer_video_param_set_display_rotation(player);
2053 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2054 __mmplayer_video_param_set_roi_area(player);
2055 if (update_all_param)
2056 __mmplayer_video_param_set_video_roi_area(player);
2058 return MM_ERROR_NONE;
2062 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
2064 MMHandleType attrs = 0;
2065 int surface_type = 0;
2066 int ret = MM_ERROR_NONE;
2070 /* check video sinkbin is created */
2071 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2072 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2074 attrs = MMPLAYER_GET_ATTRS(player);
2076 LOGE("cannot get content attribute");
2077 return MM_ERROR_PLAYER_INTERNAL;
2079 LOGD("param_name : %s", param_name);
2081 /* update display surface */
2082 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
2083 LOGD("check display surface type attribute: %d", surface_type);
2085 /* configuring display */
2086 switch (surface_type) {
2087 case MM_DISPLAY_SURFACE_OVERLAY:
2089 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
2090 if (ret != MM_ERROR_NONE)
2098 return MM_ERROR_NONE;
2102 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2104 gboolean disable_overlay = FALSE;
2105 mm_player_t* player = (mm_player_t*) hplayer;
2106 int ret = MM_ERROR_NONE;
2109 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2110 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2111 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2112 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2114 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2115 LOGW("Display control is not supported");
2116 return MM_ERROR_PLAYER_INTERNAL;
2119 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2121 if (audio_only == (bool)disable_overlay) {
2122 LOGE("It's the same with current setting: (%d)", audio_only);
2123 return MM_ERROR_NONE;
2127 LOGE("disable overlay");
2128 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2130 /* release overlay resource */
2131 if (player->video_overlay_resource != NULL) {
2132 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2133 player->video_overlay_resource);
2134 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2135 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
2138 player->video_overlay_resource = NULL;
2141 ret = mm_resource_manager_commit(player->resource_manager);
2142 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2143 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
2147 /* mark video overlay for acquire */
2148 if (player->video_overlay_resource == NULL) {
2149 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2150 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2151 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2152 &player->video_overlay_resource);
2153 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2154 LOGE("could not prepare for video_overlay resource\n");
2159 player->interrupted_by_resource = FALSE;
2160 /* acquire resources for video overlay */
2161 ret = mm_resource_manager_commit(player->resource_manager);
2162 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2163 LOGE("could not acquire resources for video playing\n");
2167 LOGD("enable overlay");
2168 __mmplayer_video_param_set_display_overlay(player);
2169 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2174 return MM_ERROR_NONE;
2178 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2180 mm_player_t* player = (mm_player_t*) hplayer;
2181 gboolean disable_overlay = FALSE;
2185 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2186 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2187 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2188 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2189 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2191 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2192 LOGW("Display control is not supported");
2193 return MM_ERROR_PLAYER_INTERNAL;
2196 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2198 *paudio_only = (bool)(disable_overlay);
2200 LOGD("audio_only : %d", *paudio_only);
2204 return MM_ERROR_NONE;
2208 __mmplayer_gst_element_link_bucket(GList* element_bucket)
2210 GList* bucket = element_bucket;
2211 MMPlayerGstElement* element = NULL;
2212 MMPlayerGstElement* prv_element = NULL;
2213 gint successful_link_count = 0;
2217 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2219 prv_element = (MMPlayerGstElement*)bucket->data;
2220 bucket = bucket->next;
2222 for (; bucket; bucket = bucket->next) {
2223 element = (MMPlayerGstElement*)bucket->data;
2225 if (element && element->gst) {
2226 if (prv_element && prv_element->gst) {
2227 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2228 LOGD("linking [%s] to [%s] success\n",
2229 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2230 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2231 successful_link_count++;
2233 LOGD("linking [%s] to [%s] failed\n",
2234 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2235 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2241 prv_element = element;
2246 return successful_link_count;
2250 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
2252 GList* bucket = element_bucket;
2253 MMPlayerGstElement* element = NULL;
2254 int successful_add_count = 0;
2258 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2259 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2261 for (; bucket; bucket = bucket->next) {
2262 element = (MMPlayerGstElement*)bucket->data;
2264 if (element && element->gst) {
2265 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2266 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
2267 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2268 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2271 successful_add_count++;
2277 return successful_add_count;
2280 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2282 mm_player_t *player = (mm_player_t*) data;
2283 GstCaps *caps = NULL;
2284 GstStructure *str = NULL;
2286 gboolean caps_ret = TRUE;
2290 MMPLAYER_RETURN_IF_FAIL(pad);
2291 MMPLAYER_RETURN_IF_FAIL(unused);
2292 MMPLAYER_RETURN_IF_FAIL(data);
2294 caps = gst_pad_get_current_caps(pad);
2298 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2302 LOGD("name = %s", name);
2304 if (strstr(name, "audio")) {
2305 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2307 if (player->audio_stream_changed_cb) {
2308 LOGE("call the audio stream changed cb");
2309 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2311 } else if (strstr(name, "video")) {
2312 if ((name = gst_structure_get_string(str, "format")))
2313 player->set_mode.video_zc = name[0] == 'S';
2315 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2317 if (player->video_stream_changed_cb) {
2318 LOGE("call the video stream changed cb");
2319 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2322 LOGW("invalid caps info");
2327 gst_caps_unref(caps);
2337 * This function is to create audio pipeline for playing.
2339 * @param player [in] handle of player
2341 * @return This function returns zero on success.
2343 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_sink_bin
2345 /* macro for code readability. just for sinkbin-creation functions */
2346 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2348 x_bin[x_id].id = x_id;\
2349 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2350 if (!x_bin[x_id].gst) {\
2351 LOGE("failed to create %s \n", x_factory);\
2354 if (x_player->ini.set_dump_element_flag)\
2355 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2358 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2362 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
2367 MMPLAYER_RETURN_IF_FAIL(player);
2369 if (player->audio_stream_buff_list) {
2370 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2371 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2374 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2375 __mmplayer_audio_stream_send_data(player, tmp);
2378 g_free(tmp->pcm_data);
2382 g_list_free(player->audio_stream_buff_list);
2383 player->audio_stream_buff_list = NULL;
2390 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
2392 MMPlayerAudioStreamDataType audio_stream = { 0, };
2395 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2397 audio_stream.bitrate = a_buffer->bitrate;
2398 audio_stream.channel = a_buffer->channel;
2399 audio_stream.depth = a_buffer->depth;
2400 audio_stream.is_little_endian = a_buffer->is_little_endian;
2401 audio_stream.channel_mask = a_buffer->channel_mask;
2402 audio_stream.data_size = a_buffer->data_size;
2403 audio_stream.data = a_buffer->pcm_data;
2405 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
2406 player->audio_stream_render_cb(&audio_stream, player->audio_stream_cb_user_param);
2412 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
2414 mm_player_t* player = (mm_player_t*) data;
2419 gint endianness = 0;
2420 guint64 channel_mask = 0;
2421 void *a_data = NULL;
2423 mm_player_audio_stream_buff_t *a_buffer = NULL;
2424 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2428 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2430 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2431 a_data = mapinfo.data;
2432 a_size = mapinfo.size;
2434 GstCaps *caps = gst_pad_get_current_caps(pad);
2435 GstStructure *structure = gst_caps_get_structure(caps, 0);
2437 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2438 gst_structure_get_int(structure, "rate", &rate);
2439 gst_structure_get_int(structure, "channels", &channel);
2440 gst_structure_get_int(structure, "depth", &depth);
2441 gst_structure_get_int(structure, "endianness", &endianness);
2442 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2443 gst_caps_unref(GST_CAPS(caps));
2445 /* In case of the sync is false, use buffer list. *
2446 * The num of buffer list depends on the num of audio channels */
2447 if (player->audio_stream_buff_list) {
2448 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2449 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2451 if (channel_mask == tmp->channel_mask) {
2452 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2453 if (tmp->data_size + a_size < tmp->buff_size) {
2454 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2455 tmp->data_size += a_size;
2457 /* send data to client */
2458 __mmplayer_audio_stream_send_data(player, tmp);
2460 if (a_size > tmp->buff_size) {
2461 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2462 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2463 if (tmp->pcm_data == NULL) {
2464 LOGE("failed to realloc data.");
2467 tmp->buff_size = a_size;
2469 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2470 memcpy(tmp->pcm_data, a_data, a_size);
2471 tmp->data_size = a_size;
2476 LOGE("data is empty in list.");
2482 /* create new audio stream data */
2483 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
2484 if (a_buffer == NULL) {
2485 LOGE("failed to alloc data.");
2488 a_buffer->bitrate = rate;
2489 a_buffer->channel = channel;
2490 a_buffer->depth = depth;
2491 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
2492 a_buffer->channel_mask = channel_mask;
2493 a_buffer->data_size = a_size;
2495 if (!player->audio_stream_sink_sync) {
2496 /* If sync is FALSE, use buffer list to reduce the IPC. */
2497 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2498 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
2499 if (a_buffer->pcm_data == NULL) {
2500 LOGE("failed to alloc data.");
2504 memcpy(a_buffer->pcm_data, a_data, a_size);
2505 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2506 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2508 /* If sync is TRUE, send data directly. */
2509 a_buffer->pcm_data = a_data;
2510 __mmplayer_audio_stream_send_data(player, a_buffer);
2515 gst_buffer_unmap(buffer, &mapinfo);
2520 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2522 mm_player_t* player = (mm_player_t*)data;
2523 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
2524 GstPad* sinkpad = NULL;
2525 GstElement *queue = NULL, *sink = NULL;
2528 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2530 queue = gst_element_factory_make("queue", NULL);
2531 if (queue == NULL) {
2532 LOGD("fail make queue\n");
2536 sink = gst_element_factory_make("fakesink", NULL);
2538 LOGD("fail make fakesink\n");
2542 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2544 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2545 LOGW("failed to link queue & sink\n");
2549 sinkpad = gst_element_get_static_pad(queue, "sink");
2551 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2552 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
2556 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
2558 gst_object_unref(sinkpad);
2559 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
2560 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2562 gst_element_set_state(sink, GST_STATE_PAUSED);
2563 gst_element_set_state(queue, GST_STATE_PAUSED);
2565 __mmplayer_add_signal_connection(player,
2567 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2569 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2576 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
2578 gst_object_unref(GST_OBJECT(queue));
2582 gst_object_unref(GST_OBJECT(sink));
2586 gst_object_unref(GST_OBJECT(sinkpad));
2593 void __mmplayer_gst_set_pulsesink_property(mm_player_t* player, MMHandleType attrs)
2595 #define MAX_PROPS_LEN 128
2596 gint latency_mode = 0;
2597 gchar *stream_type = NULL;
2598 gchar *latency = NULL;
2600 gchar stream_props[MAX_PROPS_LEN] = {0,};
2601 GstStructure *props = NULL;
2604 * It should be set after player creation through attribute.
2605 * But, it can not be changed during playing.
2608 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2610 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
2611 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
2614 LOGE("stream_type is null.");
2616 if (player->sound.focus_id)
2617 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
2618 stream_type, stream_id, player->sound.focus_id);
2620 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
2621 stream_type, stream_id);
2622 props = gst_structure_from_string(stream_props, NULL);
2623 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2624 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].",
2625 stream_type, stream_id, player->sound.focus_id, stream_props);
2626 gst_structure_free(props);
2629 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2631 switch (latency_mode) {
2632 case AUDIO_LATENCY_MODE_LOW:
2633 latency = g_strndup("low", 3);
2635 case AUDIO_LATENCY_MODE_MID:
2636 latency = g_strndup("mid", 3);
2638 case AUDIO_LATENCY_MODE_HIGH:
2639 latency = g_strndup("high", 4);
2643 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2647 LOGD("audiosink property - latency=%s", latency);
2654 void __mmplayer_gst_set_openalsink_property(mm_player_t* player)
2656 MMPlayerGstElement *audiobin = NULL;
2659 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2661 audiobin = player->pipeline->audiobin;
2663 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2664 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2665 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2667 if (player->video360_yaw_radians <= M_PI &&
2668 player->video360_yaw_radians >= -M_PI &&
2669 player->video360_pitch_radians <= M_PI_2 &&
2670 player->video360_pitch_radians >= -M_PI_2) {
2671 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2672 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
2673 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
2674 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2675 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2676 "source-orientation-y", player->video360_metadata.init_view_heading,
2677 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2684 __mmplayer_gst_fill_audio_bucket(mm_player_t *player, GList **bucket)
2686 MMPlayerGstElement *audiobin = NULL;
2687 MMHandleType attrs = 0;
2688 GList *element_bucket = NULL;
2689 GstCaps *acaps = NULL;
2690 GstPad *sink_pad = NULL;
2693 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2694 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2696 audiobin = player->pipeline->audiobin;
2697 attrs = MMPLAYER_GET_ATTRS(player);
2700 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2702 /* replaygain volume */
2703 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2704 if (player->sound.rg_enable)
2705 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2707 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2710 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2712 if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2713 gchar *dst_format = NULL;
2715 int dst_samplerate = 0;
2716 int dst_channels = 0;
2717 GstCaps *caps = NULL;
2718 char *caps_str = NULL;
2720 /* get conf. values */
2721 mm_attrs_multiple_get(player->attrs, NULL,
2722 "pcm_audioformat", &dst_format, &dst_len,
2723 "pcm_extraction_samplerate", &dst_samplerate,
2724 "pcm_extraction_channels", &dst_channels,
2727 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2730 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2731 caps = gst_caps_new_simple("audio/x-raw",
2732 "format", G_TYPE_STRING, dst_format,
2733 "rate", G_TYPE_INT, dst_samplerate,
2734 "channels", G_TYPE_INT, dst_channels,
2737 caps_str = gst_caps_to_string(caps);
2738 LOGD("new caps : %s", caps_str);
2740 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2743 gst_caps_unref(caps);
2744 MMPLAYER_FREEIF(caps_str);
2746 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2748 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2750 /* raw pad handling signal, audiosink will be added after getting signal */
2751 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2752 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2756 /* normal playback */
2759 /* for logical volume control */
2760 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2761 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2763 if (player->sound.mute) {
2764 LOGD("mute enabled");
2765 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2768 /* check if multi-channels */
2769 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
2770 GstPad *srcpad = NULL;
2771 GstCaps *caps = NULL;
2773 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
2774 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
2775 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2776 GstStructure *str = gst_caps_get_structure(caps, 0);
2778 gst_structure_get_int(str, "channels", &channels);
2779 gst_caps_unref(caps);
2781 gst_object_unref(srcpad);
2785 /* audio effect element. if audio effect is enabled */
2786 if ((strcmp(player->ini.audioeffect_element, ""))
2788 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2789 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2791 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2793 if ((!player->bypass_audio_effect)
2794 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2795 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2796 if (!_mmplayer_audio_effect_custom_apply(player))
2797 LOGI("apply audio effect(custom) setting success");
2801 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2802 && (player->set_mode.rich_audio))
2803 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2806 /* create audio sink */
2807 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2808 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2809 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2811 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2812 if (player->is_360_feature_enabled &&
2813 player->is_content_spherical &&
2815 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2816 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2817 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2819 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2821 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2823 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2824 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2825 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2826 gst_caps_unref(acaps);
2828 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2830 player->is_openal_plugin_used = TRUE;
2832 if (player->is_360_feature_enabled && player->is_content_spherical)
2833 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2834 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2837 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2838 (player->videodec_linked && player->ini.use_system_clock)) {
2839 LOGD("system clock will be used.");
2840 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2843 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2844 __mmplayer_gst_set_pulsesink_property(player, attrs);
2845 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2846 __mmplayer_gst_set_openalsink_property(player);
2849 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2850 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2852 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2853 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2854 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2855 gst_object_unref(GST_OBJECT(sink_pad));
2857 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2860 *bucket = element_bucket;
2863 return MM_ERROR_NONE;
2866 g_list_free(element_bucket);
2870 return MM_ERROR_PLAYER_INTERNAL;
2874 __mmplayer_gst_create_audio_sink_bin(mm_player_t* player)
2876 MMPlayerGstElement *first_element = NULL;
2877 MMPlayerGstElement *audiobin = NULL;
2879 GstPad *ghostpad = NULL;
2880 GList *element_bucket = NULL;
2884 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2887 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2889 LOGE("failed to allocate memory for audiobin");
2890 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2894 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2895 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2896 if (!audiobin[MMPLAYER_A_BIN].gst) {
2897 LOGE("failed to create audiobin");
2902 player->pipeline->audiobin = audiobin;
2904 /* create audio filters and audiosink */
2905 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2908 /* adding created elements to bin */
2909 LOGD("adding created elements to bin");
2910 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2913 /* linking elements in the bucket by added order. */
2914 LOGD("Linking elements in the bucket by added order.");
2915 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2918 /* get first element's sinkpad for creating ghostpad */
2919 first_element = (MMPlayerGstElement *)element_bucket->data;
2920 if (!first_element) {
2921 LOGE("failed to get first elem");
2925 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2927 LOGE("failed to get pad from first element of audiobin");
2931 ghostpad = gst_ghost_pad_new("sink", pad);
2933 LOGE("failed to create ghostpad");
2937 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2938 LOGE("failed to add ghostpad to audiobin");
2942 gst_object_unref(pad);
2944 g_list_free(element_bucket);
2947 return MM_ERROR_NONE;
2950 LOGD("ERROR : releasing audiobin");
2953 gst_object_unref(GST_OBJECT(pad));
2956 gst_object_unref(GST_OBJECT(ghostpad));
2959 g_list_free(element_bucket);
2961 /* release element which are not added to bin */
2962 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2963 /* NOTE : skip bin */
2964 if (audiobin[i].gst) {
2965 GstObject* parent = NULL;
2966 parent = gst_element_get_parent(audiobin[i].gst);
2969 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2970 audiobin[i].gst = NULL;
2972 gst_object_unref(GST_OBJECT(parent));
2976 /* release audiobin with it's childs */
2977 if (audiobin[MMPLAYER_A_BIN].gst)
2978 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2980 MMPLAYER_FREEIF(audiobin);
2982 player->pipeline->audiobin = NULL;
2984 return MM_ERROR_PLAYER_INTERNAL;
2987 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
2989 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2992 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
2994 int ret = MM_ERROR_NONE;
2996 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2997 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2999 MMPLAYER_VIDEO_BO_LOCK(player);
3001 if (player->video_bo_list) {
3002 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3003 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3004 if (tmp && tmp->bo == bo) {
3006 LOGD("release bo %p", bo);
3007 tbm_bo_unref(tmp->bo);
3008 MMPLAYER_VIDEO_BO_UNLOCK(player);
3009 MMPLAYER_VIDEO_BO_SIGNAL(player);
3014 /* hw codec is running or the list was reset for DRC. */
3015 LOGW("there is no bo list.");
3017 MMPLAYER_VIDEO_BO_UNLOCK(player);
3019 LOGW("failed to find bo %p", bo);
3024 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
3029 MMPLAYER_RETURN_IF_FAIL(player);
3031 MMPLAYER_VIDEO_BO_LOCK(player);
3032 if (player->video_bo_list) {
3033 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3034 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3035 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3038 tbm_bo_unref(tmp->bo);
3042 g_list_free(player->video_bo_list);
3043 player->video_bo_list = NULL;
3045 player->video_bo_size = 0;
3046 MMPLAYER_VIDEO_BO_UNLOCK(player);
3053 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
3056 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3057 gboolean ret = TRUE;
3059 /* check DRC, if it is, destroy the prev bo list to create again */
3060 if (player->video_bo_size != size) {
3061 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3062 __mmplayer_video_stream_destroy_bo_list(player);
3063 player->video_bo_size = size;
3066 MMPLAYER_VIDEO_BO_LOCK(player);
3068 if ((!player->video_bo_list) ||
3069 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3071 /* create bo list */
3073 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3075 if (player->video_bo_list) {
3076 /* if bo list did not created all, try it again. */
3077 idx = g_list_length(player->video_bo_list);
3078 LOGD("bo list exist(len: %d)", idx);
3081 for (; idx < player->ini.num_of_video_bo; idx++) {
3082 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
3084 LOGE("Fail to alloc bo_info.");
3087 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3089 LOGE("Fail to tbm_bo_alloc.");
3093 bo_info->used = FALSE;
3094 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3097 /* update video num buffers */
3098 player->video_num_buffers = idx;
3099 if (idx == player->ini.num_of_video_bo)
3100 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3103 MMPLAYER_VIDEO_BO_UNLOCK(player);
3107 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3111 /* get bo from list*/
3112 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3113 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3114 if (tmp && (tmp->used == FALSE)) {
3115 LOGD("found bo %p to use", tmp->bo);
3117 MMPLAYER_VIDEO_BO_UNLOCK(player);
3118 return tbm_bo_ref(tmp->bo);
3122 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3123 MMPLAYER_VIDEO_BO_UNLOCK(player);
3127 if (player->ini.video_bo_timeout <= 0) {
3128 MMPLAYER_VIDEO_BO_WAIT(player);
3130 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
3131 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3138 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3140 mm_player_t* player = (mm_player_t*)data;
3142 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3144 /* send prerolled pkt */
3145 player->video_stream_prerolled = FALSE;
3147 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3149 /* not to send prerolled pkt again */
3150 player->video_stream_prerolled = TRUE;
3154 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3156 mm_player_t* player = (mm_player_t*)data;
3157 MMPlayerVideoStreamDataType *stream = NULL;
3158 GstMemory *mem = NULL;
3161 MMPLAYER_RETURN_IF_FAIL(player);
3162 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3164 if (player->video_stream_prerolled) {
3165 player->video_stream_prerolled = FALSE;
3166 LOGD("skip the prerolled pkt not to send it again");
3170 /* clear stream data structure */
3171 stream = __mmplayer_create_stream_from_pad(pad);
3173 LOGE("failed to alloc stream");
3177 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3179 /* set size and timestamp */
3180 mem = gst_buffer_peek_memory(buffer, 0);
3181 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3182 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3184 /* check zero-copy */
3185 if (player->set_mode.video_zc &&
3186 player->set_mode.media_packet_video_stream &&
3187 gst_is_tizen_memory(mem)) {
3188 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3189 stream->internal_buffer = gst_buffer_ref(buffer);
3190 } else { /* sw codec */
3191 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3194 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3198 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3199 LOGE("failed to send video stream data.");
3206 LOGE("release video stream resource.");
3207 if (gst_is_tizen_memory(mem)) {
3209 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3211 tbm_bo_unref(stream->bo[i]);
3214 /* unref gst buffer */
3215 if (stream->internal_buffer)
3216 gst_buffer_unref(stream->internal_buffer);
3219 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3226 __mmplayer_gst_set_video360_property(mm_player_t *player)
3228 MMPlayerGstElement *videobin = NULL;
3231 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3233 videobin = player->pipeline->videobin;
3235 /* Set spatial media metadata and/or user settings to the element.
3237 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3238 "projection-type", player->video360_metadata.projection_type, NULL);
3240 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3241 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3243 if (player->video360_metadata.full_pano_width_pixels &&
3244 player->video360_metadata.full_pano_height_pixels &&
3245 player->video360_metadata.cropped_area_image_width &&
3246 player->video360_metadata.cropped_area_image_height) {
3247 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3248 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3249 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3250 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3251 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3252 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3253 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3257 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3258 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3259 "horizontal-fov", player->video360_horizontal_fov,
3260 "vertical-fov", player->video360_vertical_fov, NULL);
3263 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3264 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3265 "zoom", 1.0f / player->video360_zoom, NULL);
3268 if (player->video360_yaw_radians <= M_PI &&
3269 player->video360_yaw_radians >= -M_PI &&
3270 player->video360_pitch_radians <= M_PI_2 &&
3271 player->video360_pitch_radians >= -M_PI_2) {
3272 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3273 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
3274 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
3275 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3276 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3277 "pose-yaw", player->video360_metadata.init_view_heading,
3278 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3281 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3282 "passthrough", !player->is_video360_enabled, NULL);
3289 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3291 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3292 GList *element_bucket = NULL;
3295 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3297 /* create video360 filter */
3298 if (player->is_360_feature_enabled && player->is_content_spherical) {
3299 LOGD("create video360 element");
3300 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3301 __mmplayer_gst_set_video360_property(player);
3305 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3306 LOGD("skip creating the videoconv and rotator");
3307 return MM_ERROR_NONE;
3310 /* in case of sw codec & overlay surface type, except 360 playback.
3311 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3312 LOGD("create video converter: %s", video_csc);
3313 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3315 /* set video rotator */
3316 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
3319 *bucket = element_bucket;
3321 return MM_ERROR_NONE;
3323 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3324 g_list_free(element_bucket);
3328 return MM_ERROR_PLAYER_INTERNAL;
3332 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3334 gchar *factory_name = NULL;
3336 switch (surface_type) {
3337 case MM_DISPLAY_SURFACE_OVERLAY:
3338 if (strlen(player->ini.videosink_element_overlay) > 0)
3339 factory_name = player->ini.videosink_element_overlay;
3341 case MM_DISPLAY_SURFACE_REMOTE:
3342 if (strlen(player->ini.videosink_element_fake) > 0)
3343 factory_name = player->ini.videosink_element_fake;
3345 case MM_DISPLAY_SURFACE_NULL:
3346 LOGE("null surface type have to be handled in _decode_pad_added()");
3349 LOGE("unidentified surface type");
3353 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3354 return factory_name;
3358 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3360 gchar *factory_name = NULL;
3361 MMPlayerGstElement *videobin = NULL;
3365 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3367 videobin = player->pipeline->videobin;
3368 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3370 attrs = MMPLAYER_GET_ATTRS(player);
3372 LOGE("cannot get content attribute");
3373 return MM_ERROR_PLAYER_INTERNAL;
3376 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_REMOTE) {
3379 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3380 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3381 LOGD("OVERLAY: selected videosink is %s", factory_name);
3384 /* support shard memory with S/W codec on HawkP */
3385 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3386 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3387 "use-tbm", use_tbm, NULL);
3391 LOGE("REMOTE : add data probe at videosink");
3392 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3393 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3396 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3398 LOGD("disable last-sample");
3399 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3402 if (player->set_mode.media_packet_video_stream) {
3404 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3405 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE))
3406 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3408 __mmplayer_add_signal_connection(player,
3409 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3410 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3412 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3415 __mmplayer_add_signal_connection(player,
3416 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3417 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3419 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3424 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3425 return MM_ERROR_PLAYER_INTERNAL;
3427 if (videobin[MMPLAYER_V_SINK].gst) {
3428 GstPad *sink_pad = NULL;
3429 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3431 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3432 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3433 gst_object_unref(GST_OBJECT(sink_pad));
3435 LOGE("failed to get sink pad from videosink");
3439 return MM_ERROR_NONE;
3444 * - video overlay surface(arm/x86) : tizenwlsink
3447 __mmplayer_gst_create_video_sink_bin(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
3450 GList *element_bucket = NULL;
3451 MMPlayerGstElement *first_element = NULL;
3452 MMPlayerGstElement *videobin = NULL;
3453 gchar *videosink_factory_name = NULL;
3456 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3459 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3461 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3463 player->pipeline->videobin = videobin;
3466 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3467 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3468 if (!videobin[MMPLAYER_V_BIN].gst) {
3469 LOGE("failed to create videobin");
3473 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3476 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3477 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3479 /* additional setting for sink plug-in */
3480 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3481 LOGE("failed to set video property");
3485 /* store it as it's sink element */
3486 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3488 /* adding created elements to bin */
3489 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3490 LOGE("failed to add elements");
3494 /* Linking elements in the bucket by added order */
3495 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3496 LOGE("failed to link elements");
3500 /* get first element's sinkpad for creating ghostpad */
3501 first_element = (MMPlayerGstElement *)element_bucket->data;
3502 if (!first_element) {
3503 LOGE("failed to get first element from bucket");
3507 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3509 LOGE("failed to get pad from first element");
3513 /* create ghostpad */
3514 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3515 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3516 LOGE("failed to add ghostpad to videobin");
3519 gst_object_unref(pad);
3521 /* done. free allocated variables */
3522 g_list_free(element_bucket);
3526 return MM_ERROR_NONE;
3529 LOGE("ERROR : releasing videobin");
3530 g_list_free(element_bucket);
3533 gst_object_unref(GST_OBJECT(pad));
3535 /* release videobin with it's childs */
3536 if (videobin[MMPLAYER_V_BIN].gst)
3537 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3539 MMPLAYER_FREEIF(videobin);
3540 player->pipeline->videobin = NULL;
3542 return MM_ERROR_PLAYER_INTERNAL;
3545 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
3547 GList *element_bucket = NULL;
3548 MMPlayerGstElement *textbin = player->pipeline->textbin;
3550 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3551 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3552 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3553 "signal-handoffs", FALSE,
3556 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3557 __mmplayer_add_signal_connection(player,
3558 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3559 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3561 G_CALLBACK(__mmplayer_update_subtitle),
3564 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3565 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3567 if (!player->play_subtitle) {
3568 LOGD("add textbin sink as sink element of whole pipeline.\n");
3569 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3572 /* adding created elements to bin */
3573 LOGD("adding created elements to bin\n");
3574 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3575 LOGE("failed to add elements\n");
3579 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3580 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3581 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3583 /* linking elements in the bucket by added order. */
3584 LOGD("Linking elements in the bucket by added order.\n");
3585 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3586 LOGE("failed to link elements\n");
3590 /* done. free allocated variables */
3591 g_list_free(element_bucket);
3593 if (textbin[MMPLAYER_T_QUEUE].gst) {
3595 GstPad *ghostpad = NULL;
3597 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3599 LOGE("failed to get sink pad of text queue");
3603 ghostpad = gst_ghost_pad_new("text_sink", pad);
3604 gst_object_unref(pad);
3607 LOGE("failed to create ghostpad of textbin\n");
3611 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3612 LOGE("failed to add ghostpad to textbin\n");
3613 gst_object_unref(ghostpad);
3618 return MM_ERROR_NONE;
3621 g_list_free(element_bucket);
3623 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3624 LOGE("remove textbin sink from sink list");
3625 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3628 /* release element at __mmplayer_gst_create_text_sink_bin */
3629 return MM_ERROR_PLAYER_INTERNAL;
3632 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
3634 MMPlayerGstElement *textbin = NULL;
3635 GList *element_bucket = NULL;
3636 int surface_type = 0;
3641 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3644 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3646 LOGE("failed to allocate memory for textbin\n");
3647 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3651 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3652 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3653 if (!textbin[MMPLAYER_T_BIN].gst) {
3654 LOGE("failed to create textbin\n");
3659 player->pipeline->textbin = textbin;
3662 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3663 LOGD("surface type for subtitle : %d", surface_type);
3664 switch (surface_type) {
3665 case MM_DISPLAY_SURFACE_OVERLAY:
3666 case MM_DISPLAY_SURFACE_NULL:
3667 case MM_DISPLAY_SURFACE_REMOTE:
3668 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3669 LOGE("failed to make plain text elements\n");
3680 return MM_ERROR_NONE;
3684 LOGD("ERROR : releasing textbin\n");
3686 g_list_free(element_bucket);
3688 /* release signal */
3689 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3691 /* release element which are not added to bin */
3692 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3693 /* NOTE : skip bin */
3694 if (textbin[i].gst) {
3695 GstObject* parent = NULL;
3696 parent = gst_element_get_parent(textbin[i].gst);
3699 gst_object_unref(GST_OBJECT(textbin[i].gst));
3700 textbin[i].gst = NULL;
3702 gst_object_unref(GST_OBJECT(parent));
3707 /* release textbin with it's childs */
3708 if (textbin[MMPLAYER_T_BIN].gst)
3709 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3711 MMPLAYER_FREEIF(player->pipeline->textbin);
3712 player->pipeline->textbin = NULL;
3715 return MM_ERROR_PLAYER_INTERNAL;
3720 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
3722 MMPlayerGstElement* mainbin = NULL;
3723 MMPlayerGstElement* textbin = NULL;
3724 MMHandleType attrs = 0;
3725 GstElement *subsrc = NULL;
3726 GstElement *subparse = NULL;
3727 gchar *subtitle_uri = NULL;
3728 const gchar *charset = NULL;
3734 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3736 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3738 mainbin = player->pipeline->mainbin;
3740 attrs = MMPLAYER_GET_ATTRS(player);
3742 LOGE("cannot get content attribute\n");
3743 return MM_ERROR_PLAYER_INTERNAL;
3746 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3747 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3748 LOGE("subtitle uri is not proper filepath.\n");
3749 return MM_ERROR_PLAYER_INVALID_URI;
3752 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3753 LOGE("failed to get storage info of subtitle path");
3754 return MM_ERROR_PLAYER_INVALID_URI;
3757 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
3759 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3760 player->subtitle_language_list = NULL;
3761 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3763 /* create the subtitle source */
3764 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3766 LOGE("failed to create filesrc element\n");
3769 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3771 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3772 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3774 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3775 LOGW("failed to add queue\n");
3776 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3777 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3778 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3783 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3785 LOGE("failed to create subparse element\n");
3789 charset = util_get_charset(subtitle_uri);
3791 LOGD("detected charset is %s\n", charset);
3792 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3795 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3796 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3798 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3799 LOGW("failed to add subparse\n");
3800 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3801 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3802 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3806 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3807 LOGW("failed to link subsrc and subparse\n");
3811 player->play_subtitle = TRUE;
3812 player->adjust_subtitle_pos = 0;
3814 LOGD("play subtitle using subtitle file\n");
3816 if (player->pipeline->textbin == NULL) {
3817 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3818 LOGE("failed to create text sink bin. continuing without text\n");
3822 textbin = player->pipeline->textbin;
3824 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3825 LOGW("failed to add textbin\n");
3827 /* release signal */
3828 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3830 /* release textbin with it's childs */
3831 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3832 MMPLAYER_FREEIF(player->pipeline->textbin);
3833 player->pipeline->textbin = textbin = NULL;
3837 LOGD("link text input selector and textbin ghost pad");
3839 player->textsink_linked = 1;
3840 player->external_text_idx = 0;
3841 LOGI("player->textsink_linked set to 1\n");
3843 textbin = player->pipeline->textbin;
3844 LOGD("text bin has been created. reuse it.");
3845 player->external_text_idx = 1;
3848 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3849 LOGW("failed to link subparse and textbin\n");
3853 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3855 LOGE("failed to get sink pad from textsink to probe data");
3859 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3860 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3862 gst_object_unref(pad);
3865 /* create dot. for debugging */
3866 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3869 return MM_ERROR_NONE;
3872 /* release text pipeline resource */
3873 player->textsink_linked = 0;
3875 /* release signal */
3876 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3878 if (player->pipeline->textbin) {
3879 LOGE("remove textbin");
3881 /* release textbin with it's childs */
3882 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3883 MMPLAYER_FREEIF(player->pipeline->textbin);
3884 player->pipeline->textbin = NULL;
3888 /* release subtitle elem */
3889 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3890 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3892 return MM_ERROR_PLAYER_INTERNAL;
3896 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3898 mm_player_t* player = (mm_player_t*) data;
3899 MMMessageParamType msg = {0, };
3900 GstClockTime duration = 0;
3901 gpointer text = NULL;
3902 guint text_size = 0;
3903 gboolean ret = TRUE;
3904 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3908 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3909 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3911 if (player->is_subtitle_force_drop) {
3912 LOGW("subtitle is dropped forcedly.");
3916 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3917 text = mapinfo.data;
3918 text_size = mapinfo.size;
3919 duration = GST_BUFFER_DURATION(buffer);
3921 if (player->set_mode.subtitle_off) {
3922 LOGD("subtitle is OFF.\n");
3926 if (!text || (text_size == 0)) {
3927 LOGD("There is no subtitle to be displayed.\n");
3931 msg.data = (void *) text;
3932 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3934 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
3936 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3937 gst_buffer_unmap(buffer, &mapinfo);
3944 static GstPadProbeReturn
3945 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3947 mm_player_t *player = (mm_player_t *) u_data;
3948 GstClockTime cur_timestamp = 0;
3949 gint64 adjusted_timestamp = 0;
3950 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3952 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3954 if (player->set_mode.subtitle_off) {
3955 LOGD("subtitle is OFF.\n");
3959 if (player->adjust_subtitle_pos == 0) {
3960 LOGD("nothing to do");
3964 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3965 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3967 if (adjusted_timestamp < 0) {
3968 LOGD("adjusted_timestamp under zero");
3973 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3974 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3975 GST_TIME_ARGS(cur_timestamp),
3976 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3978 return GST_PAD_PROBE_OK;
3980 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
3984 /* check player and subtitlebin are created */
3985 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3986 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3988 if (position == 0) {
3989 LOGD("nothing to do\n");
3991 return MM_ERROR_NONE;
3995 case MM_PLAYER_POS_FORMAT_TIME:
3997 /* check current postion */
3998 player->adjust_subtitle_pos = position;
4000 LOGD("save adjust_subtitle_pos in player") ;
4006 LOGW("invalid format.\n");
4008 return MM_ERROR_INVALID_ARGUMENT;
4014 return MM_ERROR_NONE;
4018 * This function is to create audio or video pipeline for playing.
4020 * @param player [in] handle of player
4022 * @return This function returns zero on success.
4027 __mmplayer_gst_create_pipeline(mm_player_t* player)
4029 int ret = MM_ERROR_NONE;
4030 MMPlayerGstElement *mainbin = NULL;
4031 MMHandleType attrs = 0;
4032 gint mode = MM_PLAYER_PD_MODE_NONE;
4035 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4037 /* get profile attribute */
4038 attrs = MMPLAYER_GET_ATTRS(player);
4040 LOGE("failed to get content attribute");
4044 /* create pipeline handles */
4045 if (player->pipeline) {
4046 LOGE("pipeline should be released before create new one");
4050 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
4051 if (player->pipeline == NULL)
4054 /* create mainbin */
4055 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
4056 if (mainbin == NULL)
4059 /* create pipeline */
4060 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4061 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4062 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4063 LOGE("failed to create pipeline");
4068 player->pipeline->mainbin = mainbin;
4071 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
4072 player->pd_mode = mode;
4074 /* create the source and decoder elements */
4075 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4076 ret = __mmplayer_gst_build_es_pipeline(player);
4077 } else if (MMPLAYER_IS_HTTP_STREAMING(player) && MMPLAYER_IS_HTTP_PD(player)) {
4078 ret = __mmplayer_gst_build_pd_pipeline(player);
4080 ret = __mmplayer_gst_build_pipeline(player);
4083 if (ret != MM_ERROR_NONE) {
4084 LOGE("failed to create some elements");
4088 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4089 if (__mmplayer_check_subtitle(player)) {
4090 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE)
4091 LOGE("failed to create text pipeline");
4095 ret = __mmplayer_gst_add_bus_watch(player);
4096 if (ret != MM_ERROR_NONE) {
4097 LOGE("failed to add bus watch");
4102 return MM_ERROR_NONE;
4105 __mmplayer_gst_destroy_pipeline(player);
4106 return MM_ERROR_PLAYER_INTERNAL;
4110 __mmplayer_reset_gapless_state(mm_player_t* player)
4113 MMPLAYER_RETURN_IF_FAIL(player
4115 && player->pipeline->audiobin
4116 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4118 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
4125 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
4128 int ret = MM_ERROR_NONE;
4132 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4134 /* cleanup stuffs */
4135 MMPLAYER_FREEIF(player->type);
4136 player->have_dynamic_pad = FALSE;
4137 player->no_more_pad = FALSE;
4138 player->num_dynamic_pad = 0;
4139 player->demux_pad_index = 0;
4141 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4142 player->subtitle_language_list = NULL;
4143 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4145 __mmplayer_reset_gapless_state(player);
4147 if (player->streamer) {
4148 __mm_player_streaming_deinitialize(player->streamer);
4149 __mm_player_streaming_destroy(player->streamer);
4150 player->streamer = NULL;
4153 /* cleanup unlinked mime type */
4154 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4155 MMPLAYER_FREEIF(player->unlinked_video_mime);
4156 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4158 /* cleanup running stuffs */
4159 __mmplayer_cancel_eos_timer(player);
4161 /* cleanup gst stuffs */
4162 if (player->pipeline) {
4163 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
4164 GstTagList* tag_list = player->pipeline->tag_list;
4166 /* first we need to disconnect all signal hander */
4167 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4170 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4171 MMPlayerGstElement* videobin = player->pipeline->videobin;
4172 MMPlayerGstElement* textbin = player->pipeline->textbin;
4173 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4174 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4175 gst_object_unref(bus);
4177 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4178 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4179 if (ret != MM_ERROR_NONE) {
4180 LOGE("fail to change state to NULL\n");
4181 return MM_ERROR_PLAYER_INTERNAL;
4184 LOGW("succeeded in changing state to NULL\n");
4186 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4189 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4190 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4192 /* free avsysaudiosink
4193 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4194 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4196 MMPLAYER_FREEIF(audiobin);
4197 MMPLAYER_FREEIF(videobin);
4198 MMPLAYER_FREEIF(textbin);
4199 MMPLAYER_FREEIF(mainbin);
4203 gst_tag_list_free(tag_list);
4205 MMPLAYER_FREEIF(player->pipeline);
4207 MMPLAYER_FREEIF(player->album_art);
4209 if (player->v_stream_caps) {
4210 gst_caps_unref(player->v_stream_caps);
4211 player->v_stream_caps = NULL;
4213 if (player->a_stream_caps) {
4214 gst_caps_unref(player->a_stream_caps);
4215 player->a_stream_caps = NULL;
4218 if (player->s_stream_caps) {
4219 gst_caps_unref(player->s_stream_caps);
4220 player->s_stream_caps = NULL;
4222 __mmplayer_track_destroy(player);
4224 if (player->sink_elements)
4225 g_list_free(player->sink_elements);
4226 player->sink_elements = NULL;
4228 if (player->bufmgr) {
4229 tbm_bufmgr_deinit(player->bufmgr);
4230 player->bufmgr = NULL;
4233 LOGW("finished destroy pipeline\n");
4240 static int __mmplayer_gst_realize(mm_player_t* player)
4243 int ret = MM_ERROR_NONE;
4247 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4249 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4251 ret = __mmplayer_gst_create_pipeline(player);
4253 LOGE("failed to create pipeline\n");
4257 /* set pipeline state to READY */
4258 /* NOTE : state change to READY must be performed sync. */
4259 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4260 ret = __mmplayer_gst_set_state(player,
4261 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4263 if (ret != MM_ERROR_NONE) {
4264 /* return error if failed to set state */
4265 LOGE("failed to set READY state");
4269 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4271 /* create dot before error-return. for debugging */
4272 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4279 static int __mmplayer_gst_unrealize(mm_player_t* player)
4281 int ret = MM_ERROR_NONE;
4285 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4287 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4288 MMPLAYER_PRINT_STATE(player);
4290 /* release miscellaneous information */
4291 __mmplayer_release_misc(player);
4293 /* destroy pipeline */
4294 ret = __mmplayer_gst_destroy_pipeline(player);
4295 if (ret != MM_ERROR_NONE) {
4296 LOGE("failed to destory pipeline\n");
4300 /* release miscellaneous information.
4301 these info needs to be released after pipeline is destroyed. */
4302 __mmplayer_release_misc_post(player);
4304 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4312 __mmplayer_gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
4317 LOGW("set_message_callback is called with invalid player handle\n");
4318 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4321 player->msg_cb = callback;
4322 player->msg_cb_param = user_param;
4324 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
4328 return MM_ERROR_NONE;
4331 int __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
4333 int ret = MM_ERROR_NONE;
4338 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
4339 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
4340 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
4342 memset(data, 0, sizeof(MMPlayerParseProfile));
4344 if (strstr(uri, "es_buff://")) {
4345 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4346 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4347 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4348 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4350 tmp = g_ascii_strdown(uri, strlen(uri));
4351 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4352 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4354 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4356 } else if (strstr(uri, "mms://")) {
4357 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4358 } else if ((path = strstr(uri, "mem://"))) {
4359 ret = __mmplayer_set_mem_uri(data, path, param);
4361 ret = __mmplayer_set_file_uri(data, uri);
4364 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4365 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4366 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4367 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4369 /* dump parse result */
4370 SECURE_LOGW("incoming uri : %s\n", uri);
4371 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
4372 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4380 __mmplayer_can_do_interrupt(mm_player_t *player)
4382 if (!player || !player->pipeline || !player->attrs) {
4383 LOGW("not initialized");
4387 if (player->audio_stream_render_cb) {
4388 LOGW("not support in pcm extraction mode");
4392 /* check if seeking */
4393 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4394 MMMessageParamType msg_param;
4395 memset(&msg_param, 0, sizeof(MMMessageParamType));
4396 msg_param.code = MM_ERROR_PLAYER_SEEK;
4397 player->seek_state = MMPLAYER_SEEK_NONE;
4398 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4402 /* check other thread */
4403 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4404 LOGW("locked already, cmd state : %d", player->cmd);
4406 /* check application command */
4407 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4408 LOGW("playing.. should wait cmd lock then, will be interrupted");
4410 /* lock will be released at mrp_resource_release_cb() */
4411 MMPLAYER_CMD_LOCK(player);
4414 LOGW("nothing to do");
4417 LOGW("can interrupt immediately");
4421 FAILED: /* with CMD UNLOCKED */
4424 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4429 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4432 mm_player_t *player = NULL;
4436 if (user_data == NULL) {
4437 LOGE("- user_data is null\n");
4440 player = (mm_player_t *)user_data;
4442 /* do something to release resource here.
4443 * player stop and interrupt forwarding */
4444 if (!__mmplayer_can_do_interrupt(player)) {
4445 LOGW("no need to interrupt, so leave");
4447 MMMessageParamType msg = {0, };
4450 player->interrupted_by_resource = TRUE;
4452 /* get last play position */
4453 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4454 LOGW("failed to get play position.");
4456 msg.union_type = MM_MSG_UNION_TIME;
4457 msg.time.elapsed = pos;
4458 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4460 LOGD("video resource conflict so, resource will be freed by unrealizing");
4461 if (_mmplayer_unrealize((MMHandleType)player))
4462 LOGW("failed to unrealize");
4464 /* lock is called in __mmplayer_can_do_interrupt() */
4465 MMPLAYER_CMD_UNLOCK(player);
4468 if (res == player->video_overlay_resource)
4469 player->video_overlay_resource = FALSE;
4471 player->video_decoder_resource = FALSE;
4479 __mmplayer_initialize_video_roi(mm_player_t *player)
4481 player->video_roi.scale_x = 0.0;
4482 player->video_roi.scale_y = 0.0;
4483 player->video_roi.scale_width = 1.0;
4484 player->video_roi.scale_height = 1.0;
4488 _mmplayer_create_player(MMHandleType handle)
4490 int ret = MM_ERROR_PLAYER_INTERNAL;
4491 bool enabled = false;
4493 mm_player_t* player = MM_PLAYER_CAST(handle);
4497 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4499 /* initialize player state */
4500 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4501 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4502 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4503 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4505 /* check current state */
4506 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4508 /* construct attributes */
4509 player->attrs = _mmplayer_construct_attribute(handle);
4511 if (!player->attrs) {
4512 LOGE("Failed to construct attributes\n");
4516 /* initialize gstreamer with configured parameter */
4517 if (!__mmplayer_init_gstreamer(player)) {
4518 LOGE("Initializing gstreamer failed\n");
4519 _mmplayer_deconstruct_attribute(handle);
4523 /* create lock. note that g_tread_init() has already called in gst_init() */
4524 g_mutex_init(&player->fsink_lock);
4526 /* create update tag lock */
4527 g_mutex_init(&player->update_tag_lock);
4529 /* create gapless play mutex */
4530 g_mutex_init(&player->gapless_play_thread_mutex);
4532 /* create gapless play cond */
4533 g_cond_init(&player->gapless_play_thread_cond);
4535 /* create gapless play thread */
4536 player->gapless_play_thread =
4537 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4538 if (!player->gapless_play_thread) {
4539 LOGE("failed to create gapless play thread");
4540 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4541 g_mutex_clear(&player->gapless_play_thread_mutex);
4542 g_cond_clear(&player->gapless_play_thread_cond);
4546 player->bus_msg_q = g_queue_new();
4547 if (!player->bus_msg_q) {
4548 LOGE("failed to create queue for bus_msg");
4549 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4553 ret = _mmplayer_initialize_video_capture(player);
4554 if (ret != MM_ERROR_NONE) {
4555 LOGE("failed to initialize video capture\n");
4559 /* initialize resource manager */
4560 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
4561 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
4562 &player->resource_manager)) {
4563 LOGE("failed to initialize resource manager\n");
4564 ret = MM_ERROR_PLAYER_INTERNAL;
4568 if (MMPLAYER_IS_HTTP_PD(player)) {
4569 player->pd_downloader = NULL;
4570 player->pd_file_save_path = NULL;
4573 /* create video bo lock and cond */
4574 g_mutex_init(&player->video_bo_mutex);
4575 g_cond_init(&player->video_bo_cond);
4577 /* create media stream callback mutex */
4578 g_mutex_init(&player->media_stream_cb_lock);
4580 /* create subtitle info lock and cond */
4581 g_mutex_init(&player->subtitle_info_mutex);
4582 g_cond_init(&player->subtitle_info_cond);
4584 player->streaming_type = STREAMING_SERVICE_NONE;
4586 /* give default value of audio effect setting */
4587 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4588 player->sound.rg_enable = false;
4589 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4591 player->play_subtitle = FALSE;
4592 player->has_closed_caption = FALSE;
4593 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4594 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4595 player->pending_resume = FALSE;
4596 if (player->ini.dump_element_keyword[0][0] == '\0')
4597 player->ini.set_dump_element_flag = FALSE;
4599 player->ini.set_dump_element_flag = TRUE;
4601 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4602 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4603 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4605 /* Set video360 settings to their defaults for just-created player.
4608 player->is_360_feature_enabled = FALSE;
4609 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4610 LOGI("spherical feature info: %d", enabled);
4612 player->is_360_feature_enabled = TRUE;
4614 LOGE("failed to get spherical feature info");
4617 player->is_content_spherical = FALSE;
4618 player->is_video360_enabled = TRUE;
4619 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4620 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4621 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4622 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4623 player->video360_zoom = 1.0f;
4624 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4625 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4627 __mmplayer_initialize_video_roi(player);
4629 /* set player state to null */
4630 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4631 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4633 return MM_ERROR_NONE;
4637 g_mutex_clear(&player->fsink_lock);
4639 /* free update tag lock */
4640 g_mutex_clear(&player->update_tag_lock);
4642 g_queue_free(player->bus_msg_q);
4644 /* free gapless play thread */
4645 if (player->gapless_play_thread) {
4646 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4647 player->gapless_play_thread_exit = TRUE;
4648 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4649 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4651 g_thread_join(player->gapless_play_thread);
4652 player->gapless_play_thread = NULL;
4654 g_mutex_clear(&player->gapless_play_thread_mutex);
4655 g_cond_clear(&player->gapless_play_thread_cond);
4658 /* release attributes */
4659 _mmplayer_deconstruct_attribute(handle);
4667 __mmplayer_init_gstreamer(mm_player_t* player)
4669 static gboolean initialized = FALSE;
4670 static const int max_argc = 50;
4672 gchar** argv = NULL;
4673 gchar** argv2 = NULL;
4679 LOGD("gstreamer already initialized.\n");
4684 argc = malloc(sizeof(int));
4685 argv = malloc(sizeof(gchar*) * max_argc);
4686 argv2 = malloc(sizeof(gchar*) * max_argc);
4688 if (!argc || !argv || !argv2)
4691 memset(argv, 0, sizeof(gchar*) * max_argc);
4692 memset(argv2, 0, sizeof(gchar*) * max_argc);
4696 argv[0] = g_strdup("mmplayer");
4699 for (i = 0; i < 5; i++) {
4700 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4701 if (strlen(player->ini.gst_param[i]) > 0) {
4702 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4707 /* we would not do fork for scanning plugins */
4708 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4711 /* check disable registry scan */
4712 if (player->ini.skip_rescan) {
4713 argv[*argc] = g_strdup("--gst-disable-registry-update");
4717 /* check disable segtrap */
4718 if (player->ini.disable_segtrap) {
4719 argv[*argc] = g_strdup("--gst-disable-segtrap");
4723 LOGD("initializing gstreamer with following parameter\n");
4724 LOGD("argc : %d\n", *argc);
4727 for (i = 0; i < arg_count; i++) {
4729 LOGD("argv[%d] : %s\n", i, argv2[i]);
4732 /* initializing gstreamer */
4733 if (!gst_init_check(argc, &argv, &err)) {
4734 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
4741 for (i = 0; i < arg_count; i++) {
4742 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
4743 MMPLAYER_FREEIF(argv2[i]);
4746 MMPLAYER_FREEIF(argv);
4747 MMPLAYER_FREEIF(argv2);
4748 MMPLAYER_FREEIF(argc);
4758 for (i = 0; i < arg_count; i++) {
4759 LOGD("free[%d] : %s\n", i, argv2[i]);
4760 MMPLAYER_FREEIF(argv2[i]);
4763 MMPLAYER_FREEIF(argv);
4764 MMPLAYER_FREEIF(argv2);
4765 MMPLAYER_FREEIF(argc);
4771 __mmplayer_destroy_streaming_ext(mm_player_t* player)
4773 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4775 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
4776 _mmplayer_destroy_pd_downloader((MMHandleType)player);
4777 MMPLAYER_FREEIF(player->pd_file_save_path);
4780 return MM_ERROR_NONE;
4784 __mmplayer_check_async_state_transition(mm_player_t* player)
4786 GstState element_state = GST_STATE_VOID_PENDING;
4787 GstState element_pending_state = GST_STATE_VOID_PENDING;
4788 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4789 GstElement * element = NULL;
4790 gboolean async = FALSE;
4792 /* check player handle */
4793 MMPLAYER_RETURN_IF_FAIL(player &&
4795 player->pipeline->mainbin &&
4796 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4799 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4801 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4802 LOGD("don't need to check the pipeline state");
4806 MMPLAYER_PRINT_STATE(player);
4808 /* wait for state transition */
4809 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4810 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
4812 if (ret == GST_STATE_CHANGE_FAILURE) {
4813 LOGE(" [%s] state : %s pending : %s \n",
4814 GST_ELEMENT_NAME(element),
4815 gst_element_state_get_name(element_state),
4816 gst_element_state_get_name(element_pending_state));
4818 /* dump state of all element */
4819 __mmplayer_dump_pipeline_state(player);
4824 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
4829 _mmplayer_destroy(MMHandleType handle)
4831 mm_player_t* player = MM_PLAYER_CAST(handle);
4835 /* check player handle */
4836 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4838 /* destroy can called at anytime */
4839 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4841 /* check async state transition */
4842 __mmplayer_check_async_state_transition(player);
4844 __mmplayer_destroy_streaming_ext(player);
4846 /* release gapless play thread */
4847 if (player->gapless_play_thread) {
4848 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4849 player->gapless_play_thread_exit = TRUE;
4850 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4851 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4853 LOGD("waitting for gapless play thread exit\n");
4854 g_thread_join(player->gapless_play_thread);
4855 g_mutex_clear(&player->gapless_play_thread_mutex);
4856 g_cond_clear(&player->gapless_play_thread_cond);
4857 LOGD("gapless play thread released\n");
4860 _mmplayer_release_video_capture(player);
4862 /* de-initialize resource manager */
4863 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4864 player->resource_manager))
4865 LOGE("failed to deinitialize resource manager\n");
4867 /* release pipeline */
4868 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4869 LOGE("failed to destory pipeline\n");
4870 return MM_ERROR_PLAYER_INTERNAL;
4873 g_queue_free(player->bus_msg_q);
4875 /* release subtitle info lock and cond */
4876 g_mutex_clear(&player->subtitle_info_mutex);
4877 g_cond_clear(&player->subtitle_info_cond);
4879 __mmplayer_release_dump_list(player->dump_list);
4881 /* release miscellaneous information */
4882 __mmplayer_release_misc(player);
4884 /* release miscellaneous information.
4885 these info needs to be released after pipeline is destroyed. */
4886 __mmplayer_release_misc_post(player);
4888 /* release attributes */
4889 _mmplayer_deconstruct_attribute(handle);
4892 g_mutex_clear(&player->fsink_lock);
4895 g_mutex_clear(&player->update_tag_lock);
4897 /* release video bo lock and cond */
4898 g_mutex_clear(&player->video_bo_mutex);
4899 g_cond_clear(&player->video_bo_cond);
4901 /* release media stream callback lock */
4902 g_mutex_clear(&player->media_stream_cb_lock);
4906 return MM_ERROR_NONE;
4910 __mmplayer_realize_streaming_ext(mm_player_t* player)
4912 int ret = MM_ERROR_NONE;
4915 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4917 if (MMPLAYER_IS_HTTP_PD(player)) {
4918 gboolean bret = FALSE;
4920 player->pd_downloader = _mmplayer_create_pd_downloader();
4921 if (!player->pd_downloader) {
4922 LOGE("Unable to create PD Downloader...");
4923 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
4926 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
4928 if (FALSE == bret) {
4929 LOGE("Unable to create PD Downloader...");
4930 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
4939 _mmplayer_realize(MMHandleType hplayer)
4941 mm_player_t* player = (mm_player_t*)hplayer;
4944 MMHandleType attrs = 0;
4945 int ret = MM_ERROR_NONE;
4949 /* check player handle */
4950 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4952 /* check current state */
4953 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4955 attrs = MMPLAYER_GET_ATTRS(player);
4957 LOGE("fail to get attributes.\n");
4958 return MM_ERROR_PLAYER_INTERNAL;
4960 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4961 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4963 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4964 ret = __mmplayer_parse_profile((const char*)uri, param, &player->profile);
4966 if (ret != MM_ERROR_NONE) {
4967 LOGE("failed to parse profile\n");
4972 if (uri && (strstr(uri, "es_buff://"))) {
4973 if (strstr(uri, "es_buff://push_mode"))
4974 player->es_player_push_mode = TRUE;
4976 player->es_player_push_mode = FALSE;
4979 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4980 LOGW("mms protocol is not supported format.\n");
4981 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4984 if (MMPLAYER_IS_HTTP_PD(player))
4985 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_PD_STATE_CHANGE_TIME;
4986 else if (MMPLAYER_IS_STREAMING(player))
4987 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4989 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4991 player->smooth_streaming = FALSE;
4992 player->videodec_linked = 0;
4993 player->audiodec_linked = 0;
4994 player->textsink_linked = 0;
4995 player->is_external_subtitle_present = FALSE;
4996 player->is_external_subtitle_added_now = FALSE;
4997 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4998 player->video360_metadata.is_spherical = -1;
4999 player->is_openal_plugin_used = FALSE;
5000 player->demux_pad_index = 0;
5001 player->subtitle_language_list = NULL;
5002 player->is_subtitle_force_drop = FALSE;
5003 player->last_multiwin_status = FALSE;
5005 __mmplayer_track_initialize(player);
5006 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5008 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5009 player->streamer = __mm_player_streaming_create();
5010 __mm_player_streaming_initialize(player->streamer);
5013 /* realize pipeline */
5014 ret = __mmplayer_gst_realize(player);
5015 if (ret != MM_ERROR_NONE)
5016 LOGE("fail to realize the player.\n");
5018 ret = __mmplayer_realize_streaming_ext(player);
5020 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5028 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
5031 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5033 /* destroy can called at anytime */
5034 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
5035 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
5038 return MM_ERROR_NONE;
5042 _mmplayer_unrealize(MMHandleType hplayer)
5044 mm_player_t* player = (mm_player_t*)hplayer;
5045 int ret = MM_ERROR_NONE;
5049 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5051 MMPLAYER_CMD_UNLOCK(player);
5052 /* destroy the gst bus msg thread which is created during realize.
5053 this funct have to be called before getting cmd lock. */
5054 __mmplayer_bus_msg_thread_destroy(player);
5055 MMPLAYER_CMD_LOCK(player);
5057 /* check current state */
5058 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5060 /* check async state transition */
5061 __mmplayer_check_async_state_transition(player);
5063 __mmplayer_unrealize_streaming_ext(player);
5065 /* unrealize pipeline */
5066 ret = __mmplayer_gst_unrealize(player);
5068 /* set asm stop if success */
5069 if (MM_ERROR_NONE == ret) {
5070 if (!player->interrupted_by_resource) {
5071 if (player->video_decoder_resource != NULL) {
5072 ret = mm_resource_manager_mark_for_release(player->resource_manager,
5073 player->video_decoder_resource);
5074 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5075 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
5077 player->video_decoder_resource = NULL;
5080 if (player->video_overlay_resource != NULL) {
5081 ret = mm_resource_manager_mark_for_release(player->resource_manager,
5082 player->video_overlay_resource);
5083 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5084 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
5086 player->video_overlay_resource = NULL;
5089 ret = mm_resource_manager_commit(player->resource_manager);
5090 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5091 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
5094 LOGE("failed and don't change asm state to stop");
5102 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5104 mm_player_t* player = (mm_player_t*)hplayer;
5106 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5108 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5112 _mmplayer_get_state(MMHandleType hplayer, int* state)
5114 mm_player_t *player = (mm_player_t*)hplayer;
5116 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5118 *state = MMPLAYER_CURRENT_STATE(player);
5120 return MM_ERROR_NONE;
5125 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
5127 mm_player_t* player = (mm_player_t*) hplayer;
5128 GstElement* vol_element = NULL;
5133 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5135 LOGD("volume [L]=%f:[R]=%f\n",
5136 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
5138 /* invalid factor range or not */
5139 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
5140 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
5141 LOGE("Invalid factor!(valid factor:0~1.0)\n");
5142 return MM_ERROR_INVALID_ARGUMENT;
5146 /* not support to set other value into each channel */
5147 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
5148 return MM_ERROR_INVALID_ARGUMENT;
5150 /* Save volume to handle. Currently the first array element will be saved. */
5151 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
5153 /* check pipeline handle */
5154 if (!player->pipeline || !player->pipeline->audiobin) {
5155 LOGD("audiobin is not created yet\n");
5156 LOGD("but, current stored volume will be set when it's created.\n");
5158 /* NOTE : stored volume will be used in create_audiobin
5159 * returning MM_ERROR_NONE here makes application to able to
5160 * set volume at anytime.
5162 return MM_ERROR_NONE;
5165 /* setting volume to volume element */
5166 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5169 LOGD("volume is set [%f]\n", player->sound.volume);
5170 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5175 return MM_ERROR_NONE;
5180 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
5182 mm_player_t* player = (mm_player_t*) hplayer;
5187 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5188 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5190 /* returning stored volume */
5191 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
5192 volume->level[i] = player->sound.volume;
5196 return MM_ERROR_NONE;
5200 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5202 mm_player_t* player = (mm_player_t*) hplayer;
5203 GstElement* vol_element = NULL;
5207 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5209 /* mute value shoud 0 or 1 */
5210 if (mute != 0 && mute != 1) {
5211 LOGE("bad mute value\n");
5213 /* FIXIT : definitly, we need _BAD_PARAM error code */
5214 return MM_ERROR_INVALID_ARGUMENT;
5217 player->sound.mute = mute;
5219 /* just hold mute value if pipeline is not ready */
5220 if (!player->pipeline || !player->pipeline->audiobin) {
5221 LOGD("pipeline is not ready. holding mute value\n");
5222 return MM_ERROR_NONE;
5225 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5227 /* NOTE : volume will only created when the bt is enabled */
5229 LOGD("mute : %d\n", mute);
5230 g_object_set(vol_element, "mute", mute, NULL);
5232 LOGD("volume elemnet is not created. using volume in audiosink\n");
5236 return MM_ERROR_NONE;
5240 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
5242 mm_player_t* player = (mm_player_t*) hplayer;
5246 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5247 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5249 /* just hold mute value if pipeline is not ready */
5250 if (!player->pipeline || !player->pipeline->audiobin) {
5251 LOGD("pipeline is not ready. returning stored value\n");
5252 *pmute = player->sound.mute;
5253 return MM_ERROR_NONE;
5256 *pmute = player->sound.mute;
5260 return MM_ERROR_NONE;
5264 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5266 mm_player_t* player = (mm_player_t*) hplayer;
5270 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5272 player->video_stream_changed_cb = callback;
5273 player->video_stream_changed_cb_user_param = user_param;
5274 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
5278 return MM_ERROR_NONE;
5282 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5284 mm_player_t* player = (mm_player_t*) hplayer;
5288 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5290 player->audio_stream_changed_cb = callback;
5291 player->audio_stream_changed_cb_user_param = user_param;
5292 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
5296 return MM_ERROR_NONE;
5300 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5302 mm_player_t *player = (mm_player_t*) hplayer;
5306 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5308 player->audio_stream_render_cb = callback;
5309 player->audio_stream_cb_user_param = user_param;
5310 player->audio_stream_sink_sync = sync;
5311 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5315 return MM_ERROR_NONE;
5319 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5321 mm_player_t* player = (mm_player_t*) hplayer;
5325 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5327 if (callback && !player->bufmgr)
5328 player->bufmgr = tbm_bufmgr_init(-1);
5330 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
5331 player->video_stream_cb = callback;
5332 player->video_stream_cb_user_param = user_param;
5334 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5338 return MM_ERROR_NONE;
5342 __mmplayer_start_streaming_ext(mm_player_t *player)
5344 gint ret = MM_ERROR_NONE;
5347 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5349 if (MMPLAYER_IS_HTTP_PD(player)) {
5350 if (!player->pd_downloader) {
5351 ret = __mmplayer_realize_streaming_ext(player);
5353 if (ret != MM_ERROR_NONE) {
5354 LOGE("failed to realize streaming ext\n");
5359 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
5360 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
5362 LOGE("ERROR while starting PD...\n");
5363 return MM_ERROR_PLAYER_NOT_INITIALIZED;
5365 ret = MM_ERROR_NONE;
5374 _mmplayer_start(MMHandleType hplayer)
5376 mm_player_t* player = (mm_player_t*) hplayer;
5377 gint ret = MM_ERROR_NONE;
5381 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5383 /* check current state */
5384 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5386 /* PD - start streaming */
5387 ret = __mmplayer_start_streaming_ext(player);
5388 if (ret != MM_ERROR_NONE) {
5389 LOGE("failed to start streaming ext 0x%X", ret);
5393 /* start pipeline */
5394 ret = __mmplayer_gst_start(player);
5395 if (ret != MM_ERROR_NONE)
5396 LOGE("failed to start player.\n");
5398 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5399 LOGD("force playing start even during buffering");
5400 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5408 /* NOTE: post "not supported codec message" to application
5409 * when one codec is not found during AUTOPLUGGING in MSL.
5410 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5411 * And, if any codec is not found, don't send message here.
5412 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5415 __mmplayer_handle_missed_plugin(mm_player_t* player)
5417 MMMessageParamType msg_param;
5418 memset(&msg_param, 0, sizeof(MMMessageParamType));
5419 gboolean post_msg_direct = FALSE;
5423 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5425 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
5426 player->not_supported_codec, player->can_support_codec);
5428 if (player->not_found_demuxer) {
5429 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5430 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5432 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5433 MMPLAYER_FREEIF(msg_param.data);
5435 return MM_ERROR_NONE;
5438 if (player->not_supported_codec) {
5439 if (player->can_support_codec) {
5440 // There is one codec to play
5441 post_msg_direct = TRUE;
5443 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5444 post_msg_direct = TRUE;
5447 if (post_msg_direct) {
5448 MMMessageParamType msg_param;
5449 memset(&msg_param, 0, sizeof(MMMessageParamType));
5451 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5452 LOGW("not found AUDIO codec, posting error code to application.\n");
5454 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5455 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5456 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5457 LOGW("not found VIDEO codec, posting error code to application.\n");
5459 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5460 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5463 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5465 MMPLAYER_FREEIF(msg_param.data);
5467 return MM_ERROR_NONE;
5469 // no any supported codec case
5470 LOGW("not found any codec, posting error code to application.\n");
5472 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5473 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5474 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5476 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5477 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5480 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5482 MMPLAYER_FREEIF(msg_param.data);
5488 return MM_ERROR_NONE;
5491 static void __mmplayer_check_pipeline(mm_player_t* player)
5493 GstState element_state = GST_STATE_VOID_PENDING;
5494 GstState element_pending_state = GST_STATE_VOID_PENDING;
5496 int ret = MM_ERROR_NONE;
5498 if (player->gapless.reconfigure) {
5499 LOGW("pipeline is under construction.\n");
5501 MMPLAYER_PLAYBACK_LOCK(player);
5502 MMPLAYER_PLAYBACK_UNLOCK(player);
5504 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5506 /* wait for state transition */
5507 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5509 if (ret == GST_STATE_CHANGE_FAILURE)
5510 LOGE("failed to change pipeline state within %d sec\n", timeout);
5514 /* NOTE : it should be able to call 'stop' anytime*/
5516 _mmplayer_stop(MMHandleType hplayer)
5518 mm_player_t* player = (mm_player_t*)hplayer;
5519 int ret = MM_ERROR_NONE;
5523 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5525 /* check current state */
5526 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5528 /* check pipline building state */
5529 __mmplayer_check_pipeline(player);
5530 __mmplayer_reset_gapless_state(player);
5532 /* NOTE : application should not wait for EOS after calling STOP */
5533 __mmplayer_cancel_eos_timer(player);
5535 __mmplayer_unrealize_streaming_ext(player);
5538 player->seek_state = MMPLAYER_SEEK_NONE;
5541 ret = __mmplayer_gst_stop(player);
5543 if (ret != MM_ERROR_NONE)
5544 LOGE("failed to stop player.\n");
5552 _mmplayer_pause(MMHandleType hplayer)
5554 mm_player_t* player = (mm_player_t*)hplayer;
5555 gint64 pos_nsec = 0;
5556 gboolean async = FALSE;
5557 gint ret = MM_ERROR_NONE;
5561 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5563 /* check current state */
5564 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5566 /* check pipline building state */
5567 __mmplayer_check_pipeline(player);
5569 switch (MMPLAYER_CURRENT_STATE(player)) {
5570 case MM_PLAYER_STATE_READY:
5572 /* check prepare async or not.
5573 * In the case of streaming playback, it's recommned to avoid blocking wait.
5575 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5576 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5578 /* Changing back sync of rtspsrc to async */
5579 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5580 LOGD("async prepare working mode for rtsp");
5586 case MM_PLAYER_STATE_PLAYING:
5588 /* NOTE : store current point to overcome some bad operation
5589 *(returning zero when getting current position in paused state) of some
5592 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5593 LOGW("getting current position failed in paused\n");
5595 player->last_position = pos_nsec;
5597 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5598 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5599 This causes problem is position calculation during normal pause resume scenarios also.
5600 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5601 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5602 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5603 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5609 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5610 LOGD("doing async pause in case of ms buff src");
5614 /* pause pipeline */
5615 ret = __mmplayer_gst_pause(player, async);
5617 if (ret != MM_ERROR_NONE)
5618 LOGE("failed to pause player. ret : 0x%x\n", ret);
5620 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5621 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5622 LOGE("failed to update display_rotation");
5630 /* in case of streaming, pause could take long time.*/
5632 _mmplayer_abort_pause(MMHandleType hplayer)
5634 mm_player_t* player = (mm_player_t*)hplayer;
5635 int ret = MM_ERROR_NONE;
5639 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5641 player->pipeline->mainbin,
5642 MM_ERROR_PLAYER_NOT_INITIALIZED);
5644 LOGD("set the pipeline state to READY");
5646 /* set state to READY */
5647 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5648 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5649 if (ret != MM_ERROR_NONE) {
5650 LOGE("fail to change state to READY");
5651 return MM_ERROR_PLAYER_INTERNAL;
5654 LOGD("succeeded in changing state to READY");
5660 _mmplayer_resume(MMHandleType hplayer)
5662 mm_player_t* player = (mm_player_t*)hplayer;
5663 int ret = MM_ERROR_NONE;
5664 gboolean async = FALSE;
5668 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5670 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5671 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5672 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5676 /* Changing back sync mode rtspsrc to async */
5677 LOGD("async resume for rtsp case");
5681 /* check current state */
5682 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5684 ret = __mmplayer_gst_resume(player, async);
5685 if (ret != MM_ERROR_NONE)
5686 LOGE("failed to resume player.\n");
5688 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5689 LOGD("force resume even during buffering");
5690 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5699 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5701 mm_player_t* player = (mm_player_t*)hplayer;
5702 gint64 pos_nsec = 0;
5703 int ret = MM_ERROR_NONE;
5705 signed long long start = 0, stop = 0;
5706 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5709 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5710 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5712 /* The sound of video is not supported under 0.0 and over 2.0. */
5713 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5714 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5717 _mmplayer_set_mute(hplayer, mute);
5719 if (player->playback_rate == rate)
5720 return MM_ERROR_NONE;
5722 /* If the position is reached at start potion during fast backward, EOS is posted.
5723 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5725 player->playback_rate = rate;
5727 current_state = MMPLAYER_CURRENT_STATE(player);
5729 if (current_state != MM_PLAYER_STATE_PAUSED)
5730 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5732 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5734 if ((current_state == MM_PLAYER_STATE_PAUSED)
5735 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5736 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5737 pos_nsec = player->last_position;
5742 stop = GST_CLOCK_TIME_NONE;
5744 start = GST_CLOCK_TIME_NONE;
5748 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5749 player->playback_rate,
5751 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5752 GST_SEEK_TYPE_SET, start,
5753 GST_SEEK_TYPE_SET, stop)) {
5754 LOGE("failed to set speed playback\n");
5755 return MM_ERROR_PLAYER_SEEK;
5758 LOGD("succeeded to set speed playback as %0.1f\n", rate);
5762 return MM_ERROR_NONE;;
5766 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5768 mm_player_t* player = (mm_player_t*)hplayer;
5769 int ret = MM_ERROR_NONE;
5773 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5775 /* check pipline building state */
5776 __mmplayer_check_pipeline(player);
5778 ret = __mmplayer_gst_set_position(player, position, FALSE);
5786 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5788 mm_player_t* player = (mm_player_t*)hplayer;
5789 int ret = MM_ERROR_NONE;
5791 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5793 ret = __mmplayer_gst_get_position(player, position);
5799 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5801 mm_player_t* player = (mm_player_t*)hplayer;
5802 int ret = MM_ERROR_NONE;
5804 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5805 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5807 *duration = player->duration;
5812 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
5814 mm_player_t* player = (mm_player_t*)hplayer;
5815 int ret = MM_ERROR_NONE;
5817 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5819 ret = __mmplayer_gst_get_buffer_position(player, format, start_pos, stop_pos);
5825 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5827 mm_player_t* player = (mm_player_t*)hplayer;
5828 int ret = MM_ERROR_NONE;
5832 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5834 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5842 __mmplayer_is_midi_type(gchar* str_caps)
5844 if ((g_strrstr(str_caps, "audio/midi")) ||
5845 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5846 (g_strrstr(str_caps, "application/x-smaf")) ||
5847 (g_strrstr(str_caps, "audio/x-imelody")) ||
5848 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5849 (g_strrstr(str_caps, "audio/xmf")) ||
5850 (g_strrstr(str_caps, "audio/mxmf"))) {
5859 __mmplayer_is_only_mp3_type(gchar *str_caps)
5861 if (g_strrstr(str_caps, "application/x-id3") ||
5862 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5868 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
5870 GstStructure* caps_structure = NULL;
5871 gint samplerate = 0;
5875 MMPLAYER_RETURN_IF_FAIL(player && caps);
5877 caps_structure = gst_caps_get_structure(caps, 0);
5879 /* set stream information */
5880 gst_structure_get_int(caps_structure, "rate", &samplerate);
5881 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5883 gst_structure_get_int(caps_structure, "channels", &channels);
5884 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5886 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
5890 __mmplayer_update_content_type_info(mm_player_t* player)
5893 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5895 if (__mmplayer_is_midi_type(player->type)) {
5896 player->bypass_audio_effect = TRUE;
5897 } else if (g_strrstr(player->type, "application/x-hls")) {
5898 /* If it can't know exact type when it parses uri because of redirection case,
5899 * it will be fixed by typefinder or when doing autoplugging.
5901 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5902 if (player->streamer) {
5903 player->streamer->is_adaptive_streaming = TRUE;
5904 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5905 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
5907 } else if (g_strrstr(player->type, "application/dash+xml")) {
5908 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5909 if (player->streamer) {
5910 player->streamer->is_adaptive_streaming = TRUE;
5911 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5915 LOGD("uri type : %d", player->profile.uri_type);
5920 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5921 GstCaps *caps, gpointer data)
5923 mm_player_t* player = (mm_player_t*)data;
5928 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5930 /* store type string */
5931 MMPLAYER_FREEIF(player->type);
5932 player->type = gst_caps_to_string(caps);
5934 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
5935 player, player->type, probability, gst_caps_get_size(caps));
5938 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5939 (g_strrstr(player->type, "audio/x-raw-int"))) {
5940 LOGE("not support media format\n");
5942 if (player->msg_posted == FALSE) {
5943 MMMessageParamType msg_param;
5944 memset(&msg_param, 0, sizeof(MMMessageParamType));
5946 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5947 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5949 /* don't post more if one was sent already */
5950 player->msg_posted = TRUE;
5955 __mmplayer_update_content_type_info(player);
5957 pad = gst_element_get_static_pad(tf, "src");
5959 LOGE("fail to get typefind src pad.\n");
5963 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5964 gboolean async = FALSE;
5965 LOGE("failed to autoplug %s\n", player->type);
5967 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5969 if (async && player->msg_posted == FALSE)
5970 __mmplayer_handle_missed_plugin(player);
5976 gst_object_unref(GST_OBJECT(pad));
5984 __mmplayer_gst_make_decodebin(mm_player_t* player)
5986 GstElement *decodebin = NULL;
5990 /* create decodebin */
5991 decodebin = gst_element_factory_make("decodebin", NULL);
5994 LOGE("fail to create decodebin\n");
5998 /* raw pad handling signal */
5999 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6000 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
6002 /* no-more-pad pad handling signal */
6003 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6004 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
6006 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6007 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
6009 /* This signal is emitted when a pad for which there is no further possible
6010 decoding is added to the decodebin.*/
6011 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6012 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
6014 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6015 before looking for any elements that can handle that stream.*/
6016 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6017 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6019 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6020 before looking for any elements that can handle that stream.*/
6021 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6022 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
6024 /* This signal is emitted once decodebin has finished decoding all the data.*/
6025 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6026 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
6028 /* This signal is emitted when a element is added to the bin.*/
6029 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6030 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
6037 __mmplayer_gst_make_queue2(mm_player_t *player)
6039 GstElement* queue2 = NULL;
6040 gint64 dur_bytes = 0L;
6041 guint max_buffer_size_bytes = 0;
6042 MMPlayerGstElement *mainbin = NULL;
6043 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6046 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6048 mainbin = player->pipeline->mainbin;
6050 queue2 = gst_element_factory_make("queue2", "queue2");
6052 LOGE("failed to create buffering queue element");
6056 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6057 LOGE("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6059 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6061 if (dur_bytes > 0) {
6062 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
6063 type = MUXED_BUFFER_TYPE_FILE;
6065 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6066 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6072 /* NOTE : in case of ts streaming, player cannot get the correct duration info *
6073 * skip the pull mode(file or ring buffering) setting. */
6074 if (!g_strrstr(player->type, "video/mpegts")) {
6075 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
6076 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
6078 __mm_player_streaming_set_queue2(player->streamer,
6081 max_buffer_size_bytes,
6082 player->ini.http_buffering_time,
6083 1.0, /* no meaning */
6084 player->ini.http_buffering_limit, /* no meaning */
6086 player->http_file_buffering_path,
6087 (guint64)dur_bytes);
6094 __mmplayer_gst_create_decoder(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
6096 MMPlayerGstElement* mainbin = NULL;
6097 GstElement* decodebin = NULL;
6098 GstElement* queue2 = NULL;
6099 GstPad* sinkpad = NULL;
6100 GstPad* qsrcpad = NULL;
6101 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6104 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6106 mainbin = player->pipeline->mainbin;
6108 if ((!MMPLAYER_IS_HTTP_PD(player)) && (MMPLAYER_IS_HTTP_STREAMING(player))) {
6110 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6111 LOGW("need to check: muxed buffer is not null");
6114 queue2 = __mmplayer_gst_make_queue2(player);
6116 LOGE("failed to make queue2");
6120 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6121 LOGE("failed to add buffering queue");
6125 sinkpad = gst_element_get_static_pad(queue2, "sink");
6126 qsrcpad = gst_element_get_static_pad(queue2, "src");
6128 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6129 LOGE("failed to link [%s:%s]-[%s:%s]",
6130 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6134 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6135 LOGE("failed to sync queue2 state with parent");
6139 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6140 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6144 gst_object_unref(GST_OBJECT(sinkpad));
6148 /* create decodebin */
6149 decodebin = __mmplayer_gst_make_decodebin(player);
6151 LOGE("failed to make decodebin");
6155 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6156 LOGE("failed to add decodebin\n");
6160 /* to force caps on the decodebin element and avoid reparsing stuff by
6161 * typefind. It also avoids a deadlock in the way typefind activates pads in
6162 * the state change */
6163 g_object_set(decodebin, "sink-caps", caps, NULL);
6165 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6167 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6168 LOGE("failed to link [%s:%s]-[%s:%s]",
6169 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6173 gst_object_unref(GST_OBJECT(sinkpad));
6176 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6177 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6179 /* set decodebin property about buffer in streaming playback. *
6180 * in case of HLS/DASH, it does not need to have big buffer *
6181 * because it is kind of adaptive streaming. */
6182 if (!MMPLAYER_IS_HTTP_PD(player) &&
6183 (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player))) {
6184 gdouble high_percent = 0.0;
6186 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
6187 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
6189 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
6190 GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
6192 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6193 "high-percent", (gint)high_percent,
6194 "low-percent", (gint)DEFAULT_BUFFER_LOW_PERCENT,
6195 "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
6196 "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
6197 "max-size-buffers", 0, NULL); // disable or automatic
6200 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
6201 LOGE("failed to sync decodebin state with parent\n");
6212 gst_object_unref(GST_OBJECT(sinkpad));
6215 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6216 * You need to explicitly set elements to the NULL state before
6217 * dropping the final reference, to allow them to clean up.
6219 gst_element_set_state(queue2, GST_STATE_NULL);
6221 /* And, it still has a parent "player".
6222 * You need to let the parent manage the object instead of unreffing the object directly.
6224 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6225 gst_object_unref(queue2);
6230 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6231 * You need to explicitly set elements to the NULL state before
6232 * dropping the final reference, to allow them to clean up.
6234 gst_element_set_state(decodebin, GST_STATE_NULL);
6236 /* And, it still has a parent "player".
6237 * You need to let the parent manage the object instead of unreffing the object directly.
6240 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6241 gst_object_unref(decodebin);
6249 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
6253 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6254 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6256 LOGD("class : %s, mime : %s \n", factory_class, mime);
6258 /* add missing plugin */
6259 /* NOTE : msl should check missing plugin for image mime type.
6260 * Some motion jpeg clips can have playable audio track.
6261 * So, msl have to play audio after displaying popup written video format not supported.
6263 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6264 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6265 LOGD("not found demuxer\n");
6266 player->not_found_demuxer = TRUE;
6267 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6273 if (!g_strrstr(factory_class, "Demuxer")) {
6274 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6275 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
6276 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6278 /* check that clip have multi tracks or not */
6279 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6280 LOGD("video plugin is already linked\n");
6282 LOGW("add VIDEO to missing plugin\n");
6283 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6284 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6286 } else if (g_str_has_prefix(mime, "audio")) {
6287 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6288 LOGD("audio plugin is already linked\n");
6290 LOGW("add AUDIO to missing plugin\n");
6291 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6292 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6300 return MM_ERROR_NONE;
6305 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6307 mm_player_t* player = (mm_player_t*)data;
6311 MMPLAYER_RETURN_IF_FAIL(player);
6313 /* remove fakesink. */
6314 if (!__mmplayer_gst_remove_fakesink(player,
6315 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6316 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6317 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6318 * source element are not same. To overcome this situation, this function will called
6319 * several places and several times. Therefore, this is not an error case.
6324 LOGD("[handle: %p] pipeline has completely constructed", player);
6326 if ((player->ini.async_start) &&
6327 (player->msg_posted == FALSE) &&
6328 (player->cmd >= MMPLAYER_COMMAND_START))
6329 __mmplayer_handle_missed_plugin(player);
6331 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6335 __mmplayer_check_profile(void)
6338 static int profile_tv = -1;
6340 if (__builtin_expect(profile_tv != -1, 1))
6343 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6344 switch (*profileName) {
6359 __mmplayer_get_next_uri(mm_player_t *player)
6361 MMPlayerParseProfile profile;
6363 guint num_of_list = 0;
6366 num_of_list = g_list_length(player->uri_info.uri_list);
6367 uri_idx = player->uri_info.uri_idx;
6369 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6370 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6371 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6373 LOGW("next uri does not exist");
6377 if (__mmplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
6378 LOGE("failed to parse profile");
6382 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6383 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6384 LOGW("uri type is not supported(%d)", profile.uri_type);
6388 LOGD("success to find next uri %d", uri_idx);
6392 if (uri_idx == num_of_list) {
6393 LOGE("failed to find next uri");
6397 player->uri_info.uri_idx = uri_idx;
6398 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6400 if (mmf_attrs_commit(player->attrs)) {
6401 LOGE("failed to commit");
6405 SECURE_LOGD("next playback uri: %s", uri);
6410 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6412 #define REPEAT_COUNT_INFINITELY -1
6413 #define REPEAT_COUNT_MIN 2
6415 MMHandleType attrs = 0;
6416 gint mode = MM_PLAYER_PD_MODE_NONE;
6420 guint num_of_list = 0;
6421 int profile_tv = -1;
6425 LOGD("checking for gapless play option");
6427 if (player->pipeline->textbin) {
6428 LOGE("subtitle path is enabled. gapless play is not supported.\n");
6432 attrs = MMPLAYER_GET_ATTRS(player);
6434 LOGE("fail to get attributes.\n");
6438 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6440 /* gapless playback is not supported in case of video at TV profile. */
6441 profile_tv = __mmplayer_check_profile();
6442 if (profile_tv && video) {
6443 LOGW("not support video gapless playback");
6447 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
6454 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6455 LOGE("failed to get play count");
6457 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6458 LOGE("failed to get gapless mode");
6460 /* check repeat count in case of audio */
6462 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6463 LOGW("gapless is disabled");
6467 num_of_list = g_list_length(player->uri_info.uri_list);
6469 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6471 if (num_of_list == 0) {
6472 /* audio looping path */
6473 if (count >= REPEAT_COUNT_MIN) {
6474 /* decrease play count */
6475 /* we succeeded to rewind. update play count and then wait for next EOS */
6478 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6480 /* commit attribute */
6481 if (mmf_attrs_commit(attrs))
6482 LOGE("failed to commit attribute");
6483 } else if (count != REPEAT_COUNT_INFINITELY) {
6484 LOGD("there is no next uri and no repeat");
6488 LOGD("looping cnt %d", count);
6490 /* gapless playback path */
6491 if (!__mmplayer_get_next_uri(player)) {
6492 LOGE("failed to get next uri");
6500 LOGE("unable to play gapless path. EOS will be posted soon");
6505 __mmplayer_initialize_gapless_play(mm_player_t *player)
6511 player->smooth_streaming = FALSE;
6512 player->videodec_linked = 0;
6513 player->audiodec_linked = 0;
6514 player->textsink_linked = 0;
6515 player->is_external_subtitle_present = FALSE;
6516 player->is_external_subtitle_added_now = FALSE;
6517 player->not_supported_codec = MISSING_PLUGIN_NONE;
6518 player->can_support_codec = FOUND_PLUGIN_NONE;
6519 player->pending_seek.is_pending = FALSE;
6520 player->pending_seek.pos = 0;
6521 player->msg_posted = FALSE;
6522 player->has_many_types = FALSE;
6523 player->no_more_pad = FALSE;
6524 player->not_found_demuxer = 0;
6525 player->seek_state = MMPLAYER_SEEK_NONE;
6526 player->is_subtitle_force_drop = FALSE;
6527 player->play_subtitle = FALSE;
6528 player->adjust_subtitle_pos = 0;
6530 player->total_bitrate = 0;
6531 player->total_maximum_bitrate = 0;
6533 __mmplayer_track_initialize(player);
6534 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6536 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6537 player->bitrate[i] = 0;
6538 player->maximum_bitrate[i] = 0;
6541 if (player->v_stream_caps) {
6542 gst_caps_unref(player->v_stream_caps);
6543 player->v_stream_caps = NULL;
6546 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6548 /* clean found parsers */
6549 if (player->parsers) {
6550 GList *parsers = player->parsers;
6551 for (; parsers; parsers = g_list_next(parsers)) {
6552 gchar *name = parsers->data;
6553 MMPLAYER_FREEIF(name);
6555 g_list_free(player->parsers);
6556 player->parsers = NULL;
6559 /* clean found audio decoders */
6560 if (player->audio_decoders) {
6561 GList *a_dec = player->audio_decoders;
6562 for (; a_dec; a_dec = g_list_next(a_dec)) {
6563 gchar *name = a_dec->data;
6564 MMPLAYER_FREEIF(name);
6566 g_list_free(player->audio_decoders);
6567 player->audio_decoders = NULL;
6574 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6576 MMPlayerGstElement *mainbin = NULL;
6577 MMMessageParamType msg_param = {0,};
6578 GstElement *element = NULL;
6579 MMHandleType attrs = 0;
6581 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6585 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6586 LOGE("player is not initialized");
6590 mainbin = player->pipeline->mainbin;
6591 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6593 attrs = MMPLAYER_GET_ATTRS(player);
6595 LOGE("fail to get attributes");
6599 /* Initialize Player values */
6600 __mmplayer_initialize_gapless_play(player);
6602 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6604 if (__mmplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6605 LOGE("failed to parse profile");
6606 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6610 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6611 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6612 LOGE("dash or hls is not supportable");
6613 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6617 element = __mmplayer_gst_create_source(player);
6619 LOGE("no source element was created");
6623 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6624 LOGE("failed to add source element to pipeline");
6625 gst_object_unref(GST_OBJECT(element));
6630 /* take source element */
6631 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6632 mainbin[MMPLAYER_M_SRC].gst = element;
6636 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6637 if (player->streamer == NULL) {
6638 player->streamer = __mm_player_streaming_create();
6639 __mm_player_streaming_initialize(player->streamer);
6642 elem_idx = MMPLAYER_M_TYPEFIND;
6643 element = gst_element_factory_make("typefind", "typefinder");
6644 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6645 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6647 elem_idx = MMPLAYER_M_AUTOPLUG;
6648 element = __mmplayer_gst_make_decodebin(player);
6651 /* check autoplug element is OK */
6653 LOGE("can not create element(%d)", elem_idx);
6657 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6658 LOGE("failed to add sinkbin to pipeline");
6659 gst_object_unref(GST_OBJECT(element));
6664 mainbin[elem_idx].id = elem_idx;
6665 mainbin[elem_idx].gst = element;
6667 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6668 LOGE("Failed to link src - autoplug(or typefind)");
6672 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6673 LOGE("Failed to change state of src element");
6677 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6678 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6679 LOGE("Failed to change state of decodebin");
6683 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6684 LOGE("Failed to change state of src element");
6689 player->gapless.stream_changed = TRUE;
6690 player->gapless.running = TRUE;
6696 MMPLAYER_PLAYBACK_UNLOCK(player);
6698 if (!player->msg_posted) {
6699 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6700 player->msg_posted = TRUE;
6707 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6709 mm_player_selector_t *selector = &player->selector[type];
6710 MMPlayerGstElement *sinkbin = NULL;
6711 enum MainElementID selectorId = MMPLAYER_M_NUM;
6712 enum MainElementID sinkId = MMPLAYER_M_NUM;
6713 GstPad *srcpad = NULL;
6714 GstPad *sinkpad = NULL;
6715 gboolean send_notice = FALSE;
6718 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6720 LOGD("type %d", type);
6723 case MM_PLAYER_TRACK_TYPE_AUDIO:
6724 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6725 sinkId = MMPLAYER_A_BIN;
6726 sinkbin = player->pipeline->audiobin;
6728 case MM_PLAYER_TRACK_TYPE_VIDEO:
6729 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6730 sinkId = MMPLAYER_V_BIN;
6731 sinkbin = player->pipeline->videobin;
6734 case MM_PLAYER_TRACK_TYPE_TEXT:
6735 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6736 sinkId = MMPLAYER_T_BIN;
6737 sinkbin = player->pipeline->textbin;
6740 LOGE("requested type is not supportable");
6745 if (player->pipeline->mainbin[selectorId].gst) {
6748 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6750 if (selector->event_probe_id != 0)
6751 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6752 selector->event_probe_id = 0;
6754 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6755 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6757 if (srcpad && sinkpad) {
6758 /* after getting drained signal there is no data flows, so no need to do pad_block */
6759 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6760 gst_pad_unlink(srcpad, sinkpad);
6762 /* send custom event to sink pad to handle it at video sink */
6764 LOGD("send custom event to sinkpad");
6765 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6766 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6767 gst_pad_send_event(sinkpad, event);
6771 gst_object_unref(sinkpad);
6774 gst_object_unref(srcpad);
6777 LOGD("selector release");
6779 /* release and unref requests pad from the selector */
6780 for (n = 0; n < selector->channels->len; n++) {
6781 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6782 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6784 g_ptr_array_set_size(selector->channels, 0);
6786 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6787 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6789 player->pipeline->mainbin[selectorId].gst = NULL;
6797 __mmplayer_deactivate_old_path(mm_player_t *player)
6800 MMPLAYER_RETURN_IF_FAIL(player);
6802 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6803 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6804 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6805 LOGE("deactivate selector error");
6809 __mmplayer_track_destroy(player);
6810 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6812 if (player->streamer) {
6813 __mm_player_streaming_deinitialize(player->streamer);
6814 __mm_player_streaming_destroy(player->streamer);
6815 player->streamer = NULL;
6818 MMPLAYER_PLAYBACK_LOCK(player);
6819 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6826 if (!player->msg_posted) {
6827 MMMessageParamType msg = {0,};
6830 msg.code = MM_ERROR_PLAYER_INTERNAL;
6831 LOGE("gapless_uri_play> deactivate error");
6833 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6834 player->msg_posted = TRUE;
6839 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
6841 int result = MM_ERROR_NONE;
6842 mm_player_t* player = (mm_player_t*) hplayer;
6845 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6848 player->http_file_buffering_path = (gchar*)file_path;
6849 LOGD("temp file path: %s\n", player->http_file_buffering_path);
6855 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
6857 int result = MM_ERROR_NONE;
6858 mm_player_t* player = (mm_player_t*) hplayer;
6861 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6863 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6864 if (mmf_attrs_commit(player->attrs)) {
6865 LOGE("failed to commit the original uri.\n");
6866 result = MM_ERROR_PLAYER_INTERNAL;
6868 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6869 LOGE("failed to add the original uri in the uri list.\n");
6876 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
6878 mm_player_t* player = (mm_player_t*) hplayer;
6879 guint num_of_list = 0;
6883 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6884 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6886 if (player->pipeline && player->pipeline->textbin) {
6887 LOGE("subtitle path is enabled.\n");
6888 return MM_ERROR_PLAYER_INVALID_STATE;
6891 num_of_list = g_list_length(player->uri_info.uri_list);
6893 if (is_first_path == TRUE) {
6894 if (num_of_list == 0) {
6895 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6896 LOGD("add original path : %s", uri);
6898 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6899 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6901 LOGD("change original path : %s", uri);
6904 MMHandleType attrs = 0;
6905 attrs = MMPLAYER_GET_ATTRS(player);
6907 if (num_of_list == 0) {
6908 char *original_uri = NULL;
6911 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6913 if (!original_uri) {
6914 LOGE("there is no original uri.");
6915 return MM_ERROR_PLAYER_INVALID_STATE;
6918 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6919 player->uri_info.uri_idx = 0;
6921 LOGD("add original path at first : %s(%d)", original_uri);
6925 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6926 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6930 return MM_ERROR_NONE;
6933 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
6935 mm_player_t* player = (mm_player_t*) hplayer;
6936 char *next_uri = NULL;
6937 guint num_of_list = 0;
6940 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6942 num_of_list = g_list_length(player->uri_info.uri_list);
6944 if (num_of_list > 0) {
6945 gint uri_idx = player->uri_info.uri_idx;
6947 if (uri_idx < num_of_list-1)
6952 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6953 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
6955 *uri = g_strdup(next_uri);
6959 return MM_ERROR_NONE;
6963 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
6964 GstCaps *caps, gpointer data)
6966 mm_player_t* player = (mm_player_t*)data;
6967 const gchar* klass = NULL;
6968 const gchar* mime = NULL;
6969 gchar* caps_str = NULL;
6971 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6972 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6973 caps_str = gst_caps_to_string(caps);
6975 LOGW("unknown type of caps : %s from %s",
6976 caps_str, GST_ELEMENT_NAME(elem));
6978 MMPLAYER_FREEIF(caps_str);
6980 /* There is no available codec. */
6981 __mmplayer_check_not_supported_codec(player, klass, mime);
6985 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
6986 GstCaps * caps, gpointer data)
6988 mm_player_t* player = (mm_player_t*)data;
6989 const char* mime = NULL;
6990 gboolean ret = TRUE;
6992 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6993 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6995 if (g_str_has_prefix(mime, "audio")) {
6996 GstStructure* caps_structure = NULL;
6997 gint samplerate = 0;
6999 gchar *caps_str = NULL;
7001 caps_structure = gst_caps_get_structure(caps, 0);
7002 gst_structure_get_int(caps_structure, "rate", &samplerate);
7003 gst_structure_get_int(caps_structure, "channels", &channels);
7005 if ((channels > 0 && samplerate == 0)) {
7006 LOGD("exclude audio...");
7010 caps_str = gst_caps_to_string(caps);
7011 /* set it directly because not sent by TAG */
7012 if (g_strrstr(caps_str, "mobile-xmf"))
7013 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
7014 MMPLAYER_FREEIF(caps_str);
7015 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
7016 MMMessageParamType msg_param;
7017 memset(&msg_param, 0, sizeof(MMMessageParamType));
7018 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
7019 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
7020 LOGD("video file is not supported on this device");
7022 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
7023 LOGD("already video linked");
7026 LOGD("found new stream");
7033 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
7035 int ret = MM_ERROR_NONE;
7037 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7039 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7040 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7042 LOGD("audio codec type: %d", codec_type);
7043 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7044 /* sw codec will be skipped */
7045 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7046 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7047 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7048 ret = MM_ERROR_PLAYER_INTERNAL;
7052 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7053 /* hw codec will be skipped */
7054 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7055 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7056 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7057 ret = MM_ERROR_PLAYER_INTERNAL;
7062 /* set stream information */
7063 if (!player->audiodec_linked)
7064 __mmplayer_set_audio_attrs(player, caps);
7066 /* update codec info */
7067 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7068 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7069 player->audiodec_linked = 1;
7071 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7073 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7075 LOGD("video codec type: %d", codec_type);
7076 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7077 /* sw codec is skipped */
7078 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7079 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7080 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7081 ret = MM_ERROR_PLAYER_INTERNAL;
7085 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7086 /* hw codec is skipped */
7087 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7088 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7089 ret = MM_ERROR_PLAYER_INTERNAL;
7094 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7095 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7097 /* mark video decoder for acquire */
7098 if (player->video_decoder_resource == NULL) {
7099 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
7100 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
7101 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
7102 &player->video_decoder_resource)
7103 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7104 LOGE("could not mark video_decoder resource for acquire");
7105 ret = MM_ERROR_PLAYER_INTERNAL;
7109 LOGW("video decoder resource is already acquired, skip it.");
7110 ret = MM_ERROR_PLAYER_INTERNAL;
7114 player->interrupted_by_resource = FALSE;
7115 /* acquire resources for video playing */
7116 if (mm_resource_manager_commit(player->resource_manager)
7117 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7118 LOGE("could not acquire resources for video decoding\n");
7119 ret = MM_ERROR_PLAYER_INTERNAL;
7124 /* update codec info */
7125 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7126 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7127 player->videodec_linked = 1;
7135 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
7136 GstCaps* caps, GstElementFactory* factory, gpointer data)
7138 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
7139 We are defining our own and will be removed when it actually exposed */
7141 GST_AUTOPLUG_SELECT_TRY,
7142 GST_AUTOPLUG_SELECT_EXPOSE,
7143 GST_AUTOPLUG_SELECT_SKIP
7144 } GstAutoplugSelectResult;
7146 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7147 mm_player_t* player = (mm_player_t*)data;
7149 gchar* factory_name = NULL;
7150 gchar* caps_str = NULL;
7151 const gchar* klass = NULL;
7154 factory_name = GST_OBJECT_NAME(factory);
7155 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7156 caps_str = gst_caps_to_string(caps);
7158 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7160 /* store type string */
7161 if (player->type == NULL) {
7162 player->type = gst_caps_to_string(caps);
7163 __mmplayer_update_content_type_info(player);
7166 /* filtering exclude keyword */
7167 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7168 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7169 LOGW("skipping [%s] by exculde keyword [%s]",
7170 factory_name, player->ini.exclude_element_keyword[idx]);
7172 result = GST_AUTOPLUG_SELECT_SKIP;
7177 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7178 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7179 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7180 factory_name, player->ini.unsupported_codec_keyword[idx]);
7181 result = GST_AUTOPLUG_SELECT_SKIP;
7186 /* exclude webm format */
7187 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7188 * because webm format is not supportable.
7189 * If webm is disabled in "autoplug-continue", there is no state change
7190 * failure or error because the decodebin will expose the pad directly.
7191 * It make MSL invoke _prepare_async_callback.
7192 * So, we need to disable webm format in "autoplug-select" */
7193 if (caps_str && strstr(caps_str, "webm")) {
7194 LOGW("webm is not supported");
7195 result = GST_AUTOPLUG_SELECT_SKIP;
7199 /* check factory class for filtering */
7200 /* NOTE : msl don't need to use image plugins.
7201 * So, those plugins should be skipped for error handling.
7203 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7204 LOGD("skipping [%s] by not required\n", factory_name);
7205 result = GST_AUTOPLUG_SELECT_SKIP;
7209 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7210 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7211 // TO CHECK : subtitle if needed, add subparse exception.
7212 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
7213 result = GST_AUTOPLUG_SELECT_SKIP;
7217 if (g_strrstr(factory_name, "mpegpsdemux")) {
7218 LOGD("skipping PS container - not support\n");
7219 result = GST_AUTOPLUG_SELECT_SKIP;
7223 if (g_strrstr(factory_name, "mssdemux"))
7224 player->smooth_streaming = TRUE;
7226 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7227 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7230 GstStructure *str = NULL;
7231 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7233 /* don't make video because of not required */
7234 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7235 (player->set_mode.media_packet_video_stream == FALSE)) {
7236 LOGD("no video because it's not required. -> return expose");
7237 result = GST_AUTOPLUG_SELECT_EXPOSE;
7241 /* get w/h for omx state-tune */
7242 /* FIXME: deprecated? */
7243 str = gst_caps_get_structure(caps, 0);
7244 gst_structure_get_int(str, "width", &width);
7247 if (player->v_stream_caps) {
7248 gst_caps_unref(player->v_stream_caps);
7249 player->v_stream_caps = NULL;
7252 player->v_stream_caps = gst_caps_copy(caps);
7253 LOGD("take caps for video state tune");
7254 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7258 if (g_strrstr(klass, "Codec/Decoder")) {
7259 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
7260 LOGD("skipping %s codec", factory_name);
7261 result = GST_AUTOPLUG_SELECT_SKIP;
7267 MMPLAYER_FREEIF(caps_str);
7273 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
7276 //mm_player_t* player = (mm_player_t*)data;
7277 GstCaps* caps = NULL;
7279 LOGD("[Decodebin2] pad-removed signal\n");
7281 caps = gst_pad_query_caps(new_pad, NULL);
7283 gchar* caps_str = NULL;
7284 caps_str = gst_caps_to_string(caps);
7286 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7288 MMPLAYER_FREEIF(caps_str);
7289 gst_caps_unref(caps);
7294 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7296 mm_player_t* player = (mm_player_t*)data;
7297 GstIterator *iter = NULL;
7298 GValue item = { 0, };
7300 gboolean done = FALSE;
7301 gboolean is_all_drained = TRUE;
7304 MMPLAYER_RETURN_IF_FAIL(player);
7306 LOGD("__mmplayer_gst_decode_drained");
7308 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7309 LOGW("Fail to get cmd lock");
7313 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7314 !__mmplayer_verify_gapless_play_path(player)) {
7315 LOGD("decoding is finished.");
7316 __mmplayer_reset_gapless_state(player);
7317 MMPLAYER_CMD_UNLOCK(player);
7321 player->gapless.reconfigure = TRUE;
7323 /* check decodebin src pads whether they received EOS or not */
7324 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7327 switch (gst_iterator_next(iter, &item)) {
7328 case GST_ITERATOR_OK:
7329 pad = g_value_get_object(&item);
7330 if (pad && !GST_PAD_IS_EOS(pad)) {
7331 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7332 is_all_drained = FALSE;
7335 g_value_reset(&item);
7337 case GST_ITERATOR_RESYNC:
7338 gst_iterator_resync(iter);
7340 case GST_ITERATOR_ERROR:
7341 case GST_ITERATOR_DONE:
7346 g_value_unset(&item);
7347 gst_iterator_free(iter);
7349 if (!is_all_drained) {
7350 LOGD("Wait util the all pads get EOS.");
7351 MMPLAYER_CMD_UNLOCK(player);
7356 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7357 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7359 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7360 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7361 __mmplayer_deactivate_old_path(player);
7362 MMPLAYER_CMD_UNLOCK(player);
7368 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7370 mm_player_t* player = (mm_player_t*)data;
7371 const gchar* klass = NULL;
7372 gchar* factory_name = NULL;
7374 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7375 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7377 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
7379 if (__mmplayer_add_dump_buffer_probe(player, element))
7380 LOGD("add buffer probe");
7383 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7384 gchar* selected = NULL;
7385 selected = g_strdup(GST_ELEMENT_NAME(element));
7386 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7390 if (g_strrstr(klass, "Parser")) {
7391 gchar* selected = NULL;
7393 selected = g_strdup(factory_name);
7394 player->parsers = g_list_append(player->parsers, selected);
7397 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7398 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7399 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7401 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7402 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7404 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7405 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7406 "max-video-width", player->adaptive_info.limit.width,
7407 "max-video-height", player->adaptive_info.limit.height, NULL);
7409 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
7410 /* FIXIT : first value will be overwritten if there's more
7411 * than 1 demuxer/parser
7414 //LOGD("plugged element is demuxer. take it\n");
7415 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7416 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7418 /*Added for multi audio support */ // Q. del?
7419 if (g_strrstr(klass, "Demux")) {
7420 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
7421 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
7425 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7426 int surface_type = 0;
7428 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7431 // to support trust-zone only
7432 if (g_strrstr(factory_name, "asfdemux")) {
7433 LOGD("set file-location %s\n", player->profile.uri);
7434 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7435 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7436 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
7437 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7438 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7439 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7440 (__mmplayer_is_only_mp3_type(player->type))) {
7441 LOGD("[mpegaudioparse] set streaming pull mode.");
7442 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7444 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7445 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7448 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7449 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7450 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7452 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7453 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7455 if (!MMPLAYER_IS_HTTP_PD(player) &&
7456 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7457 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7458 (MMPLAYER_IS_DASH_STREAMING(player)))) {
7459 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7460 __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time, 1.0, player->ini.http_buffering_limit);
7461 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7470 __mmplayer_release_misc(mm_player_t* player)
7473 bool cur_mode = player->set_mode.rich_audio;
7476 MMPLAYER_RETURN_IF_FAIL(player);
7478 player->video_stream_cb = NULL;
7479 player->video_stream_cb_user_param = NULL;
7480 player->video_stream_prerolled = FALSE;
7482 player->audio_stream_render_cb = NULL;
7483 player->audio_stream_cb_user_param = NULL;
7484 player->audio_stream_sink_sync = false;
7486 player->video_stream_changed_cb = NULL;
7487 player->video_stream_changed_cb_user_param = NULL;
7489 player->audio_stream_changed_cb = NULL;
7490 player->audio_stream_changed_cb_user_param = NULL;
7492 player->sent_bos = FALSE;
7493 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7495 player->seek_state = MMPLAYER_SEEK_NONE;
7497 player->total_bitrate = 0;
7498 player->total_maximum_bitrate = 0;
7500 player->not_found_demuxer = 0;
7502 player->last_position = 0;
7503 player->duration = 0;
7504 player->http_content_size = 0;
7505 player->not_supported_codec = MISSING_PLUGIN_NONE;
7506 player->can_support_codec = FOUND_PLUGIN_NONE;
7507 player->pending_seek.is_pending = FALSE;
7508 player->pending_seek.pos = 0;
7509 player->msg_posted = FALSE;
7510 player->has_many_types = FALSE;
7511 player->is_subtitle_force_drop = FALSE;
7512 player->play_subtitle = FALSE;
7513 player->adjust_subtitle_pos = 0;
7514 player->last_multiwin_status = FALSE;
7515 player->has_closed_caption = FALSE;
7516 player->set_mode.media_packet_video_stream = FALSE;
7517 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7518 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7520 player->set_mode.rich_audio = cur_mode;
7522 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7523 player->bitrate[i] = 0;
7524 player->maximum_bitrate[i] = 0;
7527 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7529 /* remove media stream cb(appsrc cb) */
7530 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7531 player->media_stream_buffer_status_cb[i] = NULL;
7532 player->media_stream_seek_data_cb[i] = NULL;
7533 player->buffer_cb_user_param[i] = NULL;
7534 player->seek_cb_user_param[i] = NULL;
7536 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7538 /* free memory related to audio effect */
7539 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7541 if (player->adaptive_info.var_list) {
7542 g_list_free_full(player->adaptive_info.var_list, g_free);
7543 player->adaptive_info.var_list = NULL;
7546 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7547 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7548 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7550 /* Reset video360 settings to their defaults in case if the pipeline is to be
7553 player->video360_metadata.is_spherical = -1;
7554 player->is_openal_plugin_used = FALSE;
7556 player->is_content_spherical = FALSE;
7557 player->is_video360_enabled = TRUE;
7558 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7559 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7560 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7561 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7562 player->video360_zoom = 1.0f;
7563 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7564 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7566 player->sound.rg_enable = false;
7568 __mmplayer_initialize_video_roi(player);
7573 __mmplayer_release_misc_post(mm_player_t* player)
7575 char *original_uri = NULL;
7578 /* player->pipeline is already released before. */
7580 MMPLAYER_RETURN_IF_FAIL(player);
7582 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7584 /* clean found parsers */
7585 if (player->parsers) {
7586 GList *parsers = player->parsers;
7587 for (; parsers; parsers = g_list_next(parsers)) {
7588 gchar *name = parsers->data;
7589 MMPLAYER_FREEIF(name);
7591 g_list_free(player->parsers);
7592 player->parsers = NULL;
7595 /* clean found audio decoders */
7596 if (player->audio_decoders) {
7597 GList *a_dec = player->audio_decoders;
7598 for (; a_dec; a_dec = g_list_next(a_dec)) {
7599 gchar *name = a_dec->data;
7600 MMPLAYER_FREEIF(name);
7602 g_list_free(player->audio_decoders);
7603 player->audio_decoders = NULL;
7606 /* clean the uri list except original uri */
7607 if (player->uri_info.uri_list) {
7608 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7610 if (player->attrs) {
7611 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7612 LOGD("restore original uri = %s\n", original_uri);
7614 if (mmf_attrs_commit(player->attrs))
7615 LOGE("failed to commit the original uri.\n");
7618 GList *uri_list = player->uri_info.uri_list;
7619 for (; uri_list; uri_list = g_list_next(uri_list)) {
7620 gchar *uri = uri_list->data;
7621 MMPLAYER_FREEIF(uri);
7623 g_list_free(player->uri_info.uri_list);
7624 player->uri_info.uri_list = NULL;
7627 /* clear the audio stream buffer list */
7628 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7630 /* clear the video stream bo list */
7631 __mmplayer_video_stream_destroy_bo_list(player);
7632 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7634 if (player->profile.input_mem.buf) {
7635 free(player->profile.input_mem.buf);
7636 player->profile.input_mem.buf = NULL;
7638 player->profile.input_mem.len = 0;
7639 player->profile.input_mem.offset = 0;
7641 player->uri_info.uri_idx = 0;
7646 __mmplayer_check_subtitle(mm_player_t* player)
7648 MMHandleType attrs = 0;
7649 char *subtitle_uri = NULL;
7653 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7655 /* get subtitle attribute */
7656 attrs = MMPLAYER_GET_ATTRS(player);
7660 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7661 if (!subtitle_uri || !strlen(subtitle_uri))
7664 SECURE_LOGD("subtitle uri is %s[%d]", subtitle_uri, strlen(subtitle_uri));
7665 player->is_external_subtitle_present = TRUE;
7673 __mmplayer_cancel_eos_timer(mm_player_t* player)
7675 MMPLAYER_RETURN_IF_FAIL(player);
7677 if (player->eos_timer) {
7678 LOGD("cancel eos timer");
7679 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7680 player->eos_timer = 0;
7687 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
7691 MMPLAYER_RETURN_IF_FAIL(player);
7692 MMPLAYER_RETURN_IF_FAIL(sink);
7694 player->sink_elements =
7695 g_list_append(player->sink_elements, sink);
7701 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
7705 MMPLAYER_RETURN_IF_FAIL(player);
7706 MMPLAYER_RETURN_IF_FAIL(sink);
7708 player->sink_elements =
7709 g_list_remove(player->sink_elements, sink);
7715 __mmplayer_add_signal_connection(mm_player_t* player, GObject* object,
7716 MMPlayerSignalType type, const gchar* signal, GCallback cb_funct, gpointer u_data)
7718 MMPlayerSignalItem* item = NULL;
7721 MMPLAYER_RETURN_IF_FAIL(player);
7723 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7724 LOGE("invalid signal type [%d]", type);
7728 item = (MMPlayerSignalItem*)g_malloc(sizeof(MMPlayerSignalItem));
7730 LOGE("cannot connect signal [%s]", signal);
7735 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7736 player->signals[type] = g_list_append(player->signals[type], item);
7742 /* NOTE : be careful with calling this api. please refer to below glib comment
7743 * glib comment : Note that there is a bug in GObject that makes this function much
7744 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7745 * will no longer be called, but, the signal handler is not currently disconnected.
7746 * If the instance is itself being freed at the same time than this doesn't matter,
7747 * since the signal will automatically be removed, but if instance persists,
7748 * then the signal handler will leak. You should not remove the signal yourself
7749 * because in a future versions of GObject, the handler will automatically be
7752 * It's possible to work around this problem in a way that will continue to work
7753 * with future versions of GObject by checking that the signal handler is still
7754 * connected before disconnected it:
7756 * if (g_signal_handler_is_connected(instance, id))
7757 * g_signal_handler_disconnect(instance, id);
7760 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
7762 GList* sig_list = NULL;
7763 MMPlayerSignalItem* item = NULL;
7767 MMPLAYER_RETURN_IF_FAIL(player);
7769 LOGD("release signals type : %d", type);
7771 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7772 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7773 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7774 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7775 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7776 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7780 sig_list = player->signals[type];
7782 for (; sig_list; sig_list = sig_list->next) {
7783 item = sig_list->data;
7785 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7786 if (g_signal_handler_is_connected(item->obj, item->sig))
7787 g_signal_handler_disconnect(item->obj, item->sig);
7790 MMPLAYER_FREEIF(item);
7793 g_list_free(player->signals[type]);
7794 player->signals[type] = NULL;
7801 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7803 mm_player_t* player = 0;
7804 int prev_display_surface_type = 0;
7805 void *prev_display_overlay = NULL;
7809 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7810 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7812 player = MM_PLAYER_CAST(handle);
7814 /* check video sinkbin is created */
7815 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7816 LOGE("Videosink is already created");
7817 return MM_ERROR_NONE;
7820 LOGD("videosink element is not yet ready");
7822 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7823 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7825 return MM_ERROR_INVALID_ARGUMENT;
7828 /* load previous attributes */
7829 if (player->attrs) {
7830 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7831 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7832 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7833 if (prev_display_surface_type == surface_type) {
7834 LOGD("incoming display surface type is same as previous one, do nothing..");
7836 return MM_ERROR_NONE;
7839 LOGE("failed to load attributes");
7841 return MM_ERROR_PLAYER_INTERNAL;
7844 /* videobin is not created yet, so we just set attributes related to display surface */
7845 LOGD("store display attribute for given surface type(%d)", surface_type);
7846 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7847 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7848 if (mmf_attrs_commit(player->attrs)) {
7849 LOGE("failed to commit attribute");
7851 return MM_ERROR_PLAYER_INTERNAL;
7855 return MM_ERROR_NONE;
7858 /* Note : if silent is true, then subtitle would not be displayed. :*/
7859 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7861 mm_player_t* player = (mm_player_t*) hplayer;
7865 /* check player handle */
7866 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7868 player->set_mode.subtitle_off = silent;
7870 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
7874 return MM_ERROR_NONE;
7877 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
7879 MMPlayerGstElement* mainbin = NULL;
7880 MMPlayerGstElement* textbin = NULL;
7881 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7882 GstState current_state = GST_STATE_VOID_PENDING;
7883 GstState element_state = GST_STATE_VOID_PENDING;
7884 GstState element_pending_state = GST_STATE_VOID_PENDING;
7886 GstEvent *event = NULL;
7887 int result = MM_ERROR_NONE;
7889 GstClock *curr_clock = NULL;
7890 GstClockTime base_time, start_time, curr_time;
7895 /* check player handle */
7896 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7898 player->pipeline->mainbin &&
7899 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7901 mainbin = player->pipeline->mainbin;
7902 textbin = player->pipeline->textbin;
7904 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7906 // sync clock with current pipeline
7907 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7908 curr_time = gst_clock_get_time(curr_clock);
7910 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7911 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7913 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7914 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7916 if (current_state > GST_STATE_READY) {
7917 // sync state with current pipeline
7918 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7919 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7920 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7922 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7923 if (GST_STATE_CHANGE_FAILURE == ret) {
7924 LOGE("fail to state change.\n");
7925 result = MM_ERROR_PLAYER_INTERNAL;
7930 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7931 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7934 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7935 gst_object_unref(curr_clock);
7938 // seek to current position
7939 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7940 result = MM_ERROR_PLAYER_INVALID_STATE;
7941 LOGE("gst_element_query_position failed, invalid state\n");
7945 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7946 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);
7948 __mmplayer_gst_send_event_to_sink(player, event);
7950 result = MM_ERROR_PLAYER_INTERNAL;
7951 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7955 /* sync state with current pipeline */
7956 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7957 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7958 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7960 return MM_ERROR_NONE;
7963 /* release text pipeline resource */
7964 player->textsink_linked = 0;
7966 /* release signal */
7967 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7969 /* release textbin with it's childs */
7970 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7971 MMPLAYER_FREEIF(player->pipeline->textbin);
7972 player->pipeline->textbin = NULL;
7974 /* release subtitle elem */
7975 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7976 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7982 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
7984 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7985 GstState current_state = GST_STATE_VOID_PENDING;
7987 MMHandleType attrs = 0;
7988 MMPlayerGstElement* mainbin = NULL;
7989 MMPlayerGstElement* textbin = NULL;
7991 gchar* subtitle_uri = NULL;
7992 int result = MM_ERROR_NONE;
7993 const gchar *charset = NULL;
7997 /* check player handle */
7998 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8000 player->pipeline->mainbin &&
8001 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8002 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8004 mainbin = player->pipeline->mainbin;
8005 textbin = player->pipeline->textbin;
8007 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8008 if (current_state < GST_STATE_READY) {
8009 result = MM_ERROR_PLAYER_INVALID_STATE;
8010 LOGE("Pipeline is not in proper state\n");
8014 attrs = MMPLAYER_GET_ATTRS(player);
8016 LOGE("cannot get content attribute\n");
8017 result = MM_ERROR_PLAYER_INTERNAL;
8021 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8022 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8023 LOGE("subtitle uri is not proper filepath\n");
8024 result = MM_ERROR_PLAYER_INVALID_URI;
8028 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8029 LOGE("failed to get storage info of subtitle path");
8030 result = MM_ERROR_PLAYER_INVALID_URI;
8034 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
8035 LOGD("new subtitle file path is [%s]\n", filepath);
8037 if (!strcmp(filepath, subtitle_uri)) {
8038 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
8041 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8042 if (mmf_attrs_commit(player->attrs)) {
8043 LOGE("failed to commit.\n");
8048 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8049 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8050 player->subtitle_language_list = NULL;
8051 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8053 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8054 if (ret != GST_STATE_CHANGE_SUCCESS) {
8055 LOGE("failed to change state of textbin to READY");
8056 result = MM_ERROR_PLAYER_INTERNAL;
8060 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8061 if (ret != GST_STATE_CHANGE_SUCCESS) {
8062 LOGE("failed to change state of subparse to READY");
8063 result = MM_ERROR_PLAYER_INTERNAL;
8067 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8068 if (ret != GST_STATE_CHANGE_SUCCESS) {
8069 LOGE("failed to change state of filesrc to READY");
8070 result = MM_ERROR_PLAYER_INTERNAL;
8074 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8076 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8078 charset = util_get_charset(filepath);
8080 LOGD("detected charset is %s\n", charset);
8081 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8084 result = _mmplayer_sync_subtitle_pipeline(player);
8091 /* API to switch between external subtitles */
8092 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
8094 int result = MM_ERROR_NONE;
8095 mm_player_t* player = (mm_player_t*)hplayer;
8100 /* check player handle */
8101 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8103 /* filepath can be null in idle state */
8105 /* check file path */
8106 if ((path = strstr(filepath, "file://")))
8107 result = util_exist_file_path(path + 7);
8109 result = util_exist_file_path(filepath);
8111 if (result != MM_ERROR_NONE) {
8112 LOGE("invalid subtitle path 0x%X", result);
8113 return result; /* file not found or permission denied */
8117 if (!player->pipeline) {
8119 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8120 if (mmf_attrs_commit(player->attrs)) {
8121 LOGE("failed to commit"); /* subtitle path will not be created */
8122 return MM_ERROR_PLAYER_INTERNAL;
8125 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8126 /* check filepath */
8127 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8129 if (!__mmplayer_check_subtitle(player)) {
8130 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8131 if (mmf_attrs_commit(player->attrs)) {
8132 LOGE("failed to commit");
8133 return MM_ERROR_PLAYER_INTERNAL;
8136 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8137 LOGE("fail to create text pipeline");
8138 return MM_ERROR_PLAYER_INTERNAL;
8141 result = _mmplayer_sync_subtitle_pipeline(player);
8143 result = __mmplayer_change_external_subtitle_language(player, filepath);
8146 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8147 player->is_external_subtitle_added_now = TRUE;
8149 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8150 if (!player->subtitle_language_list) {
8151 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8152 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8153 LOGW("subtitle language list is not updated yet");
8155 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8163 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
8165 int result = MM_ERROR_NONE;
8166 gchar* change_pad_name = NULL;
8167 GstPad* sinkpad = NULL;
8168 MMPlayerGstElement* mainbin = NULL;
8169 enum MainElementID elem_idx = MMPLAYER_M_NUM;
8170 GstCaps* caps = NULL;
8171 gint total_track_num = 0;
8175 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8176 MM_ERROR_PLAYER_NOT_INITIALIZED);
8178 LOGD("Change Track(%d) to %d\n", type, index);
8180 mainbin = player->pipeline->mainbin;
8182 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8183 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8184 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8185 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8187 /* Changing Video Track is not supported. */
8188 LOGE("Track Type Error\n");
8192 if (mainbin[elem_idx].gst == NULL) {
8193 result = MM_ERROR_PLAYER_NO_OP;
8194 LOGD("Req track doesn't exist\n");
8198 total_track_num = player->selector[type].total_track_num;
8199 if (total_track_num <= 0) {
8200 result = MM_ERROR_PLAYER_NO_OP;
8201 LOGD("Language list is not available \n");
8205 if ((index < 0) || (index >= total_track_num)) {
8206 result = MM_ERROR_INVALID_ARGUMENT;
8207 LOGD("Not a proper index : %d \n", index);
8211 /*To get the new pad from the selector*/
8212 change_pad_name = g_strdup_printf("sink_%u", index);
8213 if (change_pad_name == NULL) {
8214 result = MM_ERROR_PLAYER_INTERNAL;
8215 LOGD("Pad does not exists\n");
8219 LOGD("new active pad name: %s\n", change_pad_name);
8221 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8222 if (sinkpad == NULL) {
8223 LOGD("sinkpad is NULL");
8224 result = MM_ERROR_PLAYER_INTERNAL;
8228 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
8229 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8231 caps = gst_pad_get_current_caps(sinkpad);
8232 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8235 gst_object_unref(sinkpad);
8237 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8238 __mmplayer_set_audio_attrs(player, caps);
8242 MMPLAYER_FREEIF(change_pad_name);
8246 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
8248 int result = MM_ERROR_NONE;
8249 mm_player_t* player = NULL;
8250 MMPlayerGstElement* mainbin = NULL;
8252 gint current_active_index = 0;
8254 GstState current_state = GST_STATE_VOID_PENDING;
8255 GstEvent* event = NULL;
8260 player = (mm_player_t*)hplayer;
8261 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8263 if (!player->pipeline) {
8264 LOGE("Track %d pre setting -> %d\n", type, index);
8266 player->selector[type].active_pad_index = index;
8270 mainbin = player->pipeline->mainbin;
8272 current_active_index = player->selector[type].active_pad_index;
8274 /*If index is same as running index no need to change the pad*/
8275 if (current_active_index == index)
8278 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8279 result = MM_ERROR_PLAYER_INVALID_STATE;
8283 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8284 if (current_state < GST_STATE_PAUSED) {
8285 result = MM_ERROR_PLAYER_INVALID_STATE;
8286 LOGW("Pipeline not in porper state\n");
8290 result = __mmplayer_change_selector_pad(player, type, index);
8291 if (result != MM_ERROR_NONE) {
8292 LOGE("change selector pad error\n");
8296 player->selector[type].active_pad_index = index;
8298 if (current_state == GST_STATE_PLAYING) {
8299 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);
8301 __mmplayer_gst_send_event_to_sink(player, event);
8303 result = MM_ERROR_PLAYER_INTERNAL;
8312 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
8314 mm_player_t* player = (mm_player_t*) hplayer;
8318 /* check player handle */
8319 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8321 *silent = player->set_mode.subtitle_off;
8323 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
8327 return MM_ERROR_NONE;
8331 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8333 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8334 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8336 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8337 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8341 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8342 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8343 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8344 mm_player_dump_t *dump_s;
8345 dump_s = g_malloc(sizeof(mm_player_dump_t));
8347 if (dump_s == NULL) {
8348 LOGE("malloc fail");
8352 dump_s->dump_element_file = NULL;
8353 dump_s->dump_pad = NULL;
8354 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8356 if (dump_s->dump_pad) {
8357 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
8358 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]);
8359 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8360 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);
8361 /* add list for removed buffer probe and close FILE */
8362 player->dump_list = g_list_append(player->dump_list, dump_s);
8363 LOGD("%s sink pad added buffer probe for dump", factory_name);
8368 LOGE("failed to get %s sink pad added", factory_name);
8375 static GstPadProbeReturn
8376 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8378 FILE *dump_data = (FILE *) u_data;
8380 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8381 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8383 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
8385 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8387 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8389 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8391 return GST_PAD_PROBE_OK;
8395 __mmplayer_release_dump_list(GList *dump_list)
8398 GList *d_list = dump_list;
8399 for (; d_list; d_list = g_list_next(d_list)) {
8400 mm_player_dump_t *dump_s = d_list->data;
8401 if (dump_s->dump_pad) {
8402 if (dump_s->probe_handle_id)
8403 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8405 if (dump_s->dump_element_file) {
8406 fclose(dump_s->dump_element_file);
8407 dump_s->dump_element_file = NULL;
8409 MMPLAYER_FREEIF(dump_s);
8411 g_list_free(dump_list);
8417 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
8419 mm_player_t* player = (mm_player_t*) hplayer;
8423 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8424 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8426 *exist = player->has_closed_caption;
8430 return MM_ERROR_NONE;
8433 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
8437 // LOGD("unref internal gst buffer %p", buffer);
8438 gst_buffer_unref((GstBuffer *)buffer);
8444 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8446 mm_player_t* player = (mm_player_t*) hplayer;
8450 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8451 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8453 if (MMPLAYER_IS_HTTP_PD(player))
8454 /* consider the timeout both download pipeline and playback pipeline */
8455 *timeout = player->ini.live_state_change_timeout + PLAYER_PD_STATE_CHANGE_TIME;
8456 else if (MMPLAYER_IS_STREAMING(player))
8457 *timeout = player->ini.live_state_change_timeout;
8459 *timeout = player->ini.localplayback_state_change_timeout;
8461 LOGD("timeout = %d\n", *timeout);
8464 return MM_ERROR_NONE;
8467 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8469 mm_player_t* player = (mm_player_t*) hplayer;
8473 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8474 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8476 *num = player->video_num_buffers;
8477 *extra_num = player->video_extra_num_buffers;
8479 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8482 return MM_ERROR_NONE;
8486 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
8490 MMPLAYER_RETURN_IF_FAIL(player);
8492 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8494 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8495 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8496 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8497 player->storage_info[i].id = -1;
8498 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8500 if (path_type != MMPLAYER_PATH_MAX)
8508 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8510 int ret = MM_ERROR_NONE;
8511 mm_player_t* player = (mm_player_t*)hplayer;
8512 MMMessageParamType msg_param = {0, };
8515 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8517 LOGW("state changed storage %d:%d", id, state);
8519 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8520 return MM_ERROR_NONE;
8522 /* FIXME: text path should be handled seperately. */
8523 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8524 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8525 LOGW("external storage is removed");
8527 if (player->msg_posted == FALSE) {
8528 memset(&msg_param, 0, sizeof(MMMessageParamType));
8529 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8530 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8531 player->msg_posted = TRUE;
8534 /* unrealize the player */
8535 ret = _mmplayer_unrealize(hplayer);
8536 if (ret != MM_ERROR_NONE)
8537 LOGE("failed to unrealize");
8544 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8546 int ret = MM_ERROR_NONE;
8547 mm_player_t* player = (mm_player_t*) hplayer;
8548 int idx = 0, total = 0;
8549 gchar *result = NULL, *tmp = NULL;
8552 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8553 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8555 total = *num = g_list_length(player->adaptive_info.var_list);
8557 LOGW("There is no stream variant info.");
8561 result = g_strdup("");
8562 for (idx = 0 ; idx < total ; idx++) {
8563 VariantData *v_data = NULL;
8564 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8567 gchar data[64] = {0};
8568 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8570 tmp = g_strconcat(result, data, NULL);
8574 LOGW("There is no variant data in %d", idx);
8579 *var_info = (char *)result;
8581 LOGD("variant info %d:%s", *num, *var_info);
8586 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8588 int ret = MM_ERROR_NONE;
8589 mm_player_t* player = (mm_player_t*) hplayer;
8592 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8594 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8596 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8597 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8598 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8600 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8601 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8602 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8603 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8605 /* FIXME: seek to current position for applying new variant limitation */
8613 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8615 int ret = MM_ERROR_NONE;
8616 mm_player_t* player = (mm_player_t*) hplayer;
8619 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8620 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8622 *bandwidth = player->adaptive_info.limit.bandwidth;
8623 *width = player->adaptive_info.limit.width;
8624 *height = player->adaptive_info.limit.height;
8626 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8632 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
8634 int ret = MM_ERROR_NONE;
8635 mm_player_t* player = (mm_player_t*) hplayer;
8638 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8640 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
8641 LOGW("buffer_ms will not be applied.");
8644 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
8646 if (player->streamer == NULL) {
8647 player->streamer = __mm_player_streaming_create();
8648 __mm_player_streaming_initialize(player->streamer);
8652 player->streamer->buffering_req.prebuffer_time = buffer_ms;
8654 if (rebuffer_ms >= 0)
8655 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
8662 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
8664 int ret = MM_ERROR_NONE;
8665 mm_player_t* player = (mm_player_t*) hplayer;
8668 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8669 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8671 if (player->streamer == NULL) {
8672 player->streamer = __mm_player_streaming_create();
8673 __mm_player_streaming_initialize(player->streamer);
8676 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
8677 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8679 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
8685 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8687 #define IDX_FIRST_SW_CODEC 0
8688 mm_player_t* player = (mm_player_t*) hplayer;
8689 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8690 MMHandleType attrs = 0;
8693 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8695 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8696 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8697 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8699 switch (stream_type) {
8700 case MM_PLAYER_STREAM_TYPE_AUDIO:
8701 /* to support audio codec selection, codec info have to be added in ini file as below.
8702 audio codec element hw = xxxx
8703 audio codec element sw = avdec */
8704 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8705 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8706 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8707 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8708 LOGE("There is no audio codec info for codec_type %d", codec_type);
8709 return MM_ERROR_PLAYER_NO_OP;
8712 case MM_PLAYER_STREAM_TYPE_VIDEO:
8713 /* to support video codec selection, codec info have to be added in ini file as below.
8714 video codec element hw = omx
8715 video codec element sw = avdec */
8716 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8717 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8718 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8719 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8720 LOGE("There is no video codec info for codec_type %d", codec_type);
8721 return MM_ERROR_PLAYER_NO_OP;
8725 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8726 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8730 LOGD("update %s codec_type to %d", attr_name, codec_type);
8732 attrs = MMPLAYER_GET_ATTRS(player);
8733 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8735 if (mmf_attrs_commit(player->attrs)) {
8736 LOGE("failed to commit codec_type attributes");
8737 return MM_ERROR_PLAYER_INTERNAL;
8741 return MM_ERROR_NONE;
8745 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8747 mm_player_t* player = (mm_player_t*) hplayer;
8748 GstElement* rg_vol_element = NULL;
8752 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8754 player->sound.rg_enable = enabled;
8756 /* just hold rgvolume enable value if pipeline is not ready */
8757 if (!player->pipeline || !player->pipeline->audiobin) {
8758 LOGD("pipeline is not ready. holding rgvolume enable value\n");
8759 return MM_ERROR_NONE;
8762 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8764 if (!rg_vol_element) {
8765 LOGD("rgvolume element is not created");
8766 return MM_ERROR_PLAYER_INTERNAL;
8770 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8772 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8776 return MM_ERROR_NONE;
8780 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8782 mm_player_t* player = (mm_player_t*) hplayer;
8783 GstElement* rg_vol_element = NULL;
8784 gboolean enable = FALSE;
8788 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8789 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8791 /* just hold enable_rg value if pipeline is not ready */
8792 if (!player->pipeline || !player->pipeline->audiobin) {
8793 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
8794 *enabled = player->sound.rg_enable;
8795 return MM_ERROR_NONE;
8798 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8800 if (!rg_vol_element) {
8801 LOGD("rgvolume element is not created");
8802 return MM_ERROR_PLAYER_INTERNAL;
8805 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8810 return MM_ERROR_NONE;
8814 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8816 mm_player_t* player = (mm_player_t*) hplayer;
8817 MMHandleType attrs = 0;
8818 void *handle = NULL;
8819 int ret = MM_ERROR_NONE;
8823 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8825 attrs = MMPLAYER_GET_ATTRS(player);
8826 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8828 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8830 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8831 return MM_ERROR_PLAYER_INTERNAL;
8834 player->video_roi.scale_x = scale_x;
8835 player->video_roi.scale_y = scale_y;
8836 player->video_roi.scale_width = scale_width;
8837 player->video_roi.scale_height = scale_height;
8839 /* check video sinkbin is created */
8840 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8841 return MM_ERROR_NONE;
8843 if (!gst_video_overlay_set_video_roi_area(
8844 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8845 scale_x, scale_y, scale_width, scale_height))
8846 ret = MM_ERROR_PLAYER_INTERNAL;
8848 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8849 scale_x, scale_y, scale_width, scale_height);
8857 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8859 mm_player_t* player = (mm_player_t*) hplayer;
8860 int ret = MM_ERROR_NONE;
8864 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8865 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8867 *scale_x = player->video_roi.scale_x;
8868 *scale_y = player->video_roi.scale_y;
8869 *scale_width = player->video_roi.scale_width;
8870 *scale_height = player->video_roi.scale_height;
8872 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8873 *scale_x, *scale_y, *scale_width, *scale_height);
8879 __mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs)
8881 gboolean ret = FALSE;
8882 gint64 dur_nsec = 0;
8883 LOGD("try to update duration");
8885 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8886 player->duration = dur_nsec;
8887 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8891 if (player->duration < 0) {
8892 LOGW("duration is Non-Initialized !!!");
8893 player->duration = 0;
8896 /* update streaming service type */
8897 player->streaming_type = __mmplayer_get_stream_service_type(player);
8899 /* check duration is OK */
8900 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
8901 /* FIXIT : find another way to get duration here. */
8902 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8909 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8911 /* update audio params
8912 NOTE : We need original audio params and it can be only obtained from src pad of audio
8913 decoder. Below code only valid when we are not using 'resampler' just before
8914 'audioconverter'. */
8915 GstCaps *caps_a = NULL;
8917 gint samplerate = 0, channels = 0;
8918 GstStructure* p = NULL;
8920 LOGD("try to update audio attrs");
8922 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8923 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8925 pad = gst_element_get_static_pad(
8926 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8929 LOGW("failed to get pad from audiosink");
8933 caps_a = gst_pad_get_current_caps(pad);
8936 LOGW("not ready to get audio caps");
8937 gst_object_unref(pad);
8941 p = gst_caps_get_structure(caps_a, 0);
8943 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8945 gst_structure_get_int(p, "rate", &samplerate);
8946 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8948 gst_structure_get_int(p, "channels", &channels);
8949 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8951 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8953 gst_caps_unref(caps_a);
8954 gst_object_unref(pad);
8960 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8962 LOGD("try to update video attrs");
8964 GstCaps *caps_v = NULL;
8968 GstStructure* p = NULL;
8970 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8971 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8973 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8975 LOGD("no videosink sink pad");
8979 caps_v = gst_pad_get_current_caps(pad);
8980 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8981 if (!caps_v && player->v_stream_caps) {
8982 caps_v = player->v_stream_caps;
8983 gst_caps_ref(caps_v);
8987 LOGD("no negitiated caps from videosink");
8988 gst_object_unref(pad);
8992 p = gst_caps_get_structure(caps_v, 0);
8993 gst_structure_get_int(p, "width", &width);
8994 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8996 gst_structure_get_int(p, "height", &height);
8997 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8999 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9001 SECURE_LOGD("width : %d height : %d", width, height);
9003 gst_caps_unref(caps_v);
9004 gst_object_unref(pad);
9007 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
9008 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9015 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
9017 gboolean ret = FALSE;
9018 guint64 data_size = 0;
9022 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9023 if (!player->duration)
9026 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9027 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9028 if (stat(path, &sb) == 0)
9029 data_size = (guint64)sb.st_size;
9031 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9032 data_size = player->http_content_size;
9035 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9038 guint64 bitrate = 0;
9039 guint64 msec_dur = 0;
9041 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9043 bitrate = data_size * 8 * 1000 / msec_dur;
9044 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
9045 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
9049 LOGD("player duration is less than 0");
9053 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9054 if (player->total_bitrate) {
9055 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
9063 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile* data, const char *uri, int uri_type)
9065 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9066 data->uri_type = uri_type;
9069 __mmplayer_set_mem_uri(MMPlayerParseProfile* data, char *path, void *param)
9071 int ret = MM_ERROR_PLAYER_INVALID_URI;
9073 char *buffer = NULL;
9074 char *seperator = strchr(path, ',');
9075 char ext[100] = {0,}, size[100] = {0,};
9078 if ((buffer = strstr(path, "ext="))) {
9079 buffer += strlen("ext=");
9081 if (strlen(buffer)) {
9082 strncpy(ext, buffer, 99);
9084 if ((seperator = strchr(ext, ','))
9085 || (seperator = strchr(ext, ' '))
9086 || (seperator = strchr(ext, '\0'))) {
9087 seperator[0] = '\0';
9092 if ((buffer = strstr(path, "size="))) {
9093 buffer += strlen("size=");
9095 if (strlen(buffer) > 0) {
9096 strncpy(size, buffer, 99);
9098 if ((seperator = strchr(size, ','))
9099 || (seperator = strchr(size, ' '))
9100 || (seperator = strchr(size, '\0'))) {
9101 seperator[0] = '\0';
9104 mem_size = atoi(size);
9109 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
9111 if (mem_size && param) {
9112 if (data->input_mem.buf)
9113 free(data->input_mem.buf);
9114 data->input_mem.buf = malloc(mem_size);
9116 if (data->input_mem.buf) {
9117 memcpy(data->input_mem.buf, param, mem_size);
9118 data->input_mem.len = mem_size;
9119 ret = MM_ERROR_NONE;
9121 LOGE("failed to alloc mem %d", mem_size);
9122 ret = MM_ERROR_PLAYER_INTERNAL;
9125 data->input_mem.offset = 0;
9126 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9133 __mmplayer_set_file_uri(MMPlayerParseProfile* data, const char *uri)
9135 gchar *location = NULL;
9138 int ret = MM_ERROR_NONE;
9140 if ((path = strstr(uri, "file://"))) {
9141 location = g_filename_from_uri(uri, NULL, &err);
9142 if (!location || (err != NULL)) {
9143 LOGE("Invalid URI '%s' for filesrc: %s", path,
9144 (err != NULL) ? err->message : "unknown error");
9150 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9151 return MM_ERROR_PLAYER_INVALID_URI;
9153 LOGD("path from uri: %s", location);
9156 path = (location != NULL) ? (location) : ((char *)uri);
9159 ret = util_exist_file_path(path);
9161 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9162 if (ret == MM_ERROR_NONE) {
9163 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9164 if (util_is_sdp_file(path)) {
9165 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
9166 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9168 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9170 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9171 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9173 LOGE("invalid uri, could not play..\n");
9174 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9183 static MMPlayerVideoStreamDataType*
9184 __mmplayer_create_stream_from_pad(GstPad *pad)
9186 GstCaps *caps = NULL;
9187 GstStructure *structure = NULL;
9188 unsigned int fourcc = 0;
9189 const gchar *string_format = NULL;
9190 MMPlayerVideoStreamDataType *stream = NULL;
9192 MMPixelFormatType format;
9194 caps = gst_pad_get_current_caps(pad);
9196 LOGE("Caps is NULL.");
9200 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9201 structure = gst_caps_get_structure(caps, 0);
9202 gst_structure_get_int(structure, "width", &width);
9203 gst_structure_get_int(structure, "height", &height);
9204 string_format = gst_structure_get_string(structure, "format");
9206 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9207 format = util_get_pixtype(fourcc);
9208 gst_caps_unref(caps);
9211 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9212 LOGE("Wrong condition!!");
9216 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
9218 LOGE("failed to alloc mem for video data");
9222 stream->width = width;
9223 stream->height = height;
9224 stream->format = format;
9230 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9232 unsigned int pitch = 0;
9234 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9236 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9237 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
9238 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
9239 stream->stride[index] = pitch;
9240 stream->elevation[index] = stream->height;
9245 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
9247 if (stream->format == MM_PIXEL_FORMAT_I420) {
9248 int ret = TBM_SURFACE_ERROR_NONE;
9249 tbm_surface_h surface;
9250 tbm_surface_info_s info;
9252 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9254 ret = tbm_surface_get_info(surface, &info);
9255 if (ret != TBM_SURFACE_ERROR_NONE) {
9256 tbm_surface_destroy(surface);
9260 tbm_surface_destroy(surface);
9261 stream->stride[0] = info.planes[0].stride;
9262 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9263 stream->stride[1] = info.planes[1].stride;
9264 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9265 stream->stride[2] = info.planes[2].stride;
9266 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9267 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9268 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9269 stream->stride[0] = stream->width * 4;
9270 stream->elevation[0] = stream->height;
9271 stream->bo_size = stream->stride[0] * stream->height;
9273 LOGE("Not support format %d", stream->format);
9281 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9283 tbm_bo_handle thandle;
9285 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9286 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9287 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9291 unsigned char *src = NULL;
9292 unsigned char *dest = NULL;
9293 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9295 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9297 LOGE("fail to gst_memory_map");
9301 if (!mapinfo.data) {
9302 LOGE("data pointer is wrong");
9306 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9307 if (!stream->bo[0]) {
9308 LOGE("Fail to tbm_bo_alloc!!");
9312 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9314 LOGE("thandle pointer is wrong");
9318 if (stream->format == MM_PIXEL_FORMAT_I420) {
9319 src_stride[0] = GST_ROUND_UP_4(stream->width);
9320 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9321 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9322 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9325 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9326 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9328 for (i = 0; i < 3; i++) {
9329 src = mapinfo.data + src_offset[i];
9330 dest = thandle.ptr + dest_offset[i];
9335 for (j = 0; j < stream->height >> k; j++) {
9336 memcpy(dest, src, stream->width>>k);
9337 src += src_stride[i];
9338 dest += stream->stride[i];
9341 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9342 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9344 LOGE("Not support format %d", stream->format);
9348 tbm_bo_unmap(stream->bo[0]);
9349 gst_memory_unmap(mem, &mapinfo);
9355 tbm_bo_unmap(stream->bo[0]);
9358 gst_memory_unmap(mem, &mapinfo);