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_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
140 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
141 static int __mmplayer_gst_create_text_pipeline(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_decode_callback(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_decode_callback(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_decode_callback(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_decode_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_decode_callback(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_decode_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 decode path */
1401 if (!__mmplayer_create_decode_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1402 LOGE("failed to create audio decode path");
1410 static gboolean __mmplayer_create_text_decode_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_decode_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1430 LOGE("failed to create text decode 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_decode_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_decode_path(player, audio_selector))
1527 /* create text path followed by text-select */
1528 __mmplayer_create_text_decode_path(player, text_selector);
1531 if (player->gapless.reconfigure) {
1532 player->gapless.reconfigure = FALSE;
1533 MMPLAYER_PLAYBACK_UNLOCK(player);
1540 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
1542 mm_player_t *player = NULL;
1543 MMHandleType attrs = 0;
1544 GstElement *pipeline = NULL;
1545 GstCaps *caps = NULL;
1546 gchar *caps_str = NULL;
1547 GstStructure *str = NULL;
1548 const gchar *name = NULL;
1549 GstPad *sinkpad = NULL;
1550 GstElement *sinkbin = NULL;
1551 gboolean reusing = FALSE;
1552 GstElement *text_selector = NULL;
1553 gboolean caps_ret = TRUE;
1556 player = (mm_player_t*) data;
1558 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1559 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1561 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1563 attrs = MMPLAYER_GET_ATTRS(player);
1565 LOGE("cannot get content attribute\n");
1569 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1573 caps_str = gst_caps_to_string(caps);
1575 /* LOGD("detected mimetype : %s", name); */
1576 if (strstr(name, "audio")) {
1577 if (player->pipeline->audiobin == NULL) {
1578 if (__mmplayer_gst_create_audio_pipeline(player) != MM_ERROR_NONE) {
1579 LOGE("failed to create audiobin. continuing without audio\n");
1583 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1584 LOGD("creating audiosink bin success");
1587 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1588 LOGD("reusing audiobin\n");
1589 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
1592 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
1593 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
1595 player->audiosink_linked = 1;
1597 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
1599 LOGE("failed to get pad from sinkbin\n");
1602 } else if (strstr(name, "video")) {
1603 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1604 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1605 player->set_mode.video_zc = TRUE;
1607 if (player->pipeline->videobin == NULL) {
1608 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
1609 /* get video surface type */
1610 int surface_type = 0;
1611 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1612 LOGD("display_surface_type (%d)", surface_type);
1614 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
1615 LOGD("surface_type is NULL");
1619 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
1620 /* mark video overlay for acquire */
1621 if (player->video_overlay_resource == NULL) {
1622 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1623 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1624 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1625 &player->video_overlay_resource)
1626 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1627 LOGE("could not mark video_overlay resource for acquire\n");
1633 player->interrupted_by_resource = FALSE;
1634 /* acquire resources for video overlay */
1635 if (mm_resource_manager_commit(player->resource_manager) !=
1636 MM_RESOURCE_MANAGER_ERROR_NONE) {
1637 LOGE("could not acquire resources for video playing\n");
1641 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
1642 LOGE("failed to create videobin. continuing without video\n");
1646 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1647 LOGD("creating videosink bin success\n");
1650 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1651 LOGD("re-using videobin\n");
1652 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
1655 player->videosink_linked = 1;
1657 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
1659 LOGE("failed to get pad from sinkbin\n");
1662 } else if (strstr(name, "text")) {
1663 if (player->pipeline->textbin == NULL) {
1664 MMPlayerGstElement* mainbin = NULL;
1666 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
1667 LOGE("failed to create text sink bin. continuing without text\n");
1671 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1672 LOGD("creating textsink bin success\n");
1674 /* FIXIT : track number shouldn't be hardcoded */
1675 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
1677 player->textsink_linked = 1;
1678 LOGI("player->textsink_linked set to 1\n");
1680 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
1682 LOGE("failed to get pad from sinkbin\n");
1686 mainbin = player->pipeline->mainbin;
1688 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
1689 /* input selector */
1690 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
1691 if (!text_selector) {
1692 LOGE("failed to create subtitle input selector element\n");
1695 g_object_set(text_selector, "sync-streams", TRUE, NULL);
1697 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
1698 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
1701 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
1702 LOGE("failed to set state(READY) to sinkbin\n");
1706 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
1707 LOGW("failed to add subtitle input selector\n");
1711 LOGD("created element input-selector");
1714 LOGD("already having subtitle input selector");
1715 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1718 if (!player->textsink_linked) {
1719 LOGD("re-using textbin\n");
1722 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1724 player->textsink_linked = 1;
1725 LOGI("player->textsink_linked set to 1\n");
1727 LOGD("ignoring internal subtutle since external subtitle is available");
1730 LOGW("unknown type of elementary stream!ignoring it...\n");
1737 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
1738 LOGE("failed to set state(READY) to sinkbin\n");
1742 /* Added for multi audio support to avoid adding audio bin again*/
1744 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1745 LOGE("failed to add sinkbin to pipeline\n");
1751 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
1752 LOGE("failed to get pad from sinkbin\n");
1758 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
1759 LOGE("failed to set state(PAUSED) to sinkbin\n");
1763 if (text_selector) {
1764 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
1765 LOGE("failed to set state(PAUSED) to sinkbin\n");
1771 gst_object_unref(sinkpad);
1775 LOGD("[handle: %p] linking sink bin success", player);
1777 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1778 * streaming task. if the task blocked, then buffer will not flow to the next element
1779 *(autoplugging element). so this is special hack for streaming. please try to remove it
1781 /* dec stream count. we can remove fakesink if it's zero */
1782 if (player->num_dynamic_pad)
1783 player->num_dynamic_pad--;
1785 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
1787 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1788 __mmplayer_pipeline_complete(NULL, player);
1792 MMPLAYER_FREEIF(caps_str);
1795 gst_caps_unref(caps);
1798 gst_object_unref(GST_OBJECT(sinkpad));
1800 /* flusing out new attributes */
1801 if (mmf_attrs_commit(attrs))
1802 LOGE("failed to comit attributes\n");
1808 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int display_angle, int orientation, int *value)
1810 int required_angle = 0; /* Angle required for straight view */
1811 int rotation_angle = 0;
1813 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1814 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1816 /* Counter clockwise */
1817 switch (orientation) {
1822 required_angle = 270;
1825 required_angle = 180;
1828 required_angle = 90;
1832 rotation_angle = display_angle + required_angle;
1833 if (rotation_angle >= 360)
1834 rotation_angle -= 360;
1836 /* chech if supported or not */
1837 if (rotation_angle % 90) {
1838 LOGD("not supported rotation angle = %d", rotation_angle);
1842 switch (rotation_angle) {
1844 *value = MM_DISPLAY_ROTATION_NONE;
1847 *value = MM_DISPLAY_ROTATION_90;
1850 *value = MM_DISPLAY_ROTATION_180;
1853 *value = MM_DISPLAY_ROTATION_270;
1857 LOGD("setting rotation property value : %d", value);
1863 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
1865 /* check video sinkbin is created */
1866 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1868 player->pipeline->videobin &&
1869 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1870 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1871 MM_ERROR_PLAYER_NOT_INITIALIZED);
1873 return MM_ERROR_NONE;
1877 __mmplayer_get_video_angle(mm_player_t* player, int *display_angle, int *orientation)
1879 int display_rotation = 0;
1880 gchar *org_orient = NULL;
1881 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1884 LOGE("cannot get content attribute");
1885 return MM_ERROR_PLAYER_INTERNAL;
1888 if (display_angle) {
1889 /* update user roation */
1890 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1892 /* Counter clockwise */
1893 switch (display_rotation) {
1894 case MM_DISPLAY_ROTATION_NONE:
1897 case MM_DISPLAY_ROTATION_90:
1898 *display_angle = 90;
1900 case MM_DISPLAY_ROTATION_180:
1901 *display_angle = 180;
1903 case MM_DISPLAY_ROTATION_270:
1904 *display_angle = 270;
1907 LOGW("wrong angle type : %d", display_rotation);
1910 LOGD("check user angle: %d", *display_angle);
1914 /* Counter clockwise */
1915 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1918 if (!strcmp(org_orient, "rotate-90"))
1920 else if (!strcmp(org_orient, "rotate-180"))
1922 else if (!strcmp(org_orient, "rotate-270"))
1925 LOGD("original rotation is %s", org_orient);
1927 LOGD("content_video_orientation get fail");
1930 LOGD("check orientation: %d", *orientation);
1933 return MM_ERROR_NONE;
1937 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
1939 int rotation_value = 0;
1940 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1941 int display_angle = 0;
1944 /* check video sinkbin is created */
1945 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1948 __mmplayer_get_video_angle(player, &display_angle, &orientations);
1950 /* get rotation value to set */
1951 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1952 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1953 LOGD("set video param : rotate %d", rotation_value);
1957 __mmplayer_video_param_set_display_visible(mm_player_t* player)
1959 MMHandleType attrs = 0;
1963 /* check video sinkbin is created */
1964 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1967 attrs = MMPLAYER_GET_ATTRS(player);
1968 MMPLAYER_RETURN_IF_FAIL(attrs);
1970 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1971 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1972 LOGD("set video param : visible %d", visible);
1976 __mmplayer_video_param_set_display_method(mm_player_t* player)
1978 MMHandleType attrs = 0;
1979 int display_method = 0;
1982 /* check video sinkbin is created */
1983 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1986 attrs = MMPLAYER_GET_ATTRS(player);
1987 MMPLAYER_RETURN_IF_FAIL(attrs);
1989 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1990 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1991 LOGD("set video param : method %d", display_method);
1994 __mmplayer_video_param_set_video_roi_area(mm_player_t* player)
1996 MMHandleType attrs = 0;
1997 void *handle = NULL;
2000 /* check video sinkbin is created */
2001 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
2002 LOGW("There is no video sink");
2006 attrs = MMPLAYER_GET_ATTRS(player);
2007 MMPLAYER_RETURN_IF_FAIL(attrs);
2008 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2010 gst_video_overlay_set_video_roi_area(
2011 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2012 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2013 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2014 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2019 __mmplayer_video_param_set_roi_area(mm_player_t* player)
2021 MMHandleType attrs = 0;
2022 void *handle = NULL;
2026 int win_roi_width = 0;
2027 int win_roi_height = 0;
2030 /* check video sinkbin is created */
2031 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
2032 LOGW("There is no video sink");
2036 attrs = MMPLAYER_GET_ATTRS(player);
2037 MMPLAYER_RETURN_IF_FAIL(attrs);
2039 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2042 /* It should be set after setting window */
2043 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
2044 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
2045 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
2046 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
2048 /* After setting window handle, set display roi area */
2049 gst_video_overlay_set_display_roi_area(
2050 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2051 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2052 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2053 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2057 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
2059 MMHandleType attrs = 0;
2060 void *handle = NULL;
2062 /* check video sinkbin is created */
2063 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2066 attrs = MMPLAYER_GET_ATTRS(player);
2067 MMPLAYER_RETURN_IF_FAIL(attrs);
2069 /* common case if using overlay surface */
2070 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2073 /* default is using wl_surface_id */
2074 unsigned int wl_surface_id = 0;
2075 wl_surface_id = *(int*)handle;
2076 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
2077 gst_video_overlay_set_wl_window_wl_surface_id(
2078 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2081 /* FIXIT : is it error case? */
2082 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
2087 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
2089 bool update_all_param = FALSE;
2092 /* check video sinkbin is created */
2093 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2094 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2096 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2097 LOGE("can not find tizenwlsink");
2098 return MM_ERROR_PLAYER_INTERNAL;
2101 LOGD("param_name : %s", param_name);
2102 if (!g_strcmp0(param_name, "update_all_param"))
2103 update_all_param = TRUE;
2105 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2106 __mmplayer_video_param_set_display_overlay(player);
2107 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2108 __mmplayer_video_param_set_display_method(player);
2109 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2110 __mmplayer_video_param_set_display_visible(player);
2111 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2112 __mmplayer_video_param_set_display_rotation(player);
2113 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2114 __mmplayer_video_param_set_roi_area(player);
2115 if (update_all_param)
2116 __mmplayer_video_param_set_video_roi_area(player);
2118 return MM_ERROR_NONE;
2122 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
2124 MMHandleType attrs = 0;
2125 int surface_type = 0;
2126 int ret = MM_ERROR_NONE;
2130 /* check video sinkbin is created */
2131 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2132 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2134 attrs = MMPLAYER_GET_ATTRS(player);
2136 LOGE("cannot get content attribute");
2137 return MM_ERROR_PLAYER_INTERNAL;
2139 LOGD("param_name : %s", param_name);
2141 /* update display surface */
2142 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
2143 LOGD("check display surface type attribute: %d", surface_type);
2145 /* configuring display */
2146 switch (surface_type) {
2147 case MM_DISPLAY_SURFACE_OVERLAY:
2149 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
2150 if (ret != MM_ERROR_NONE)
2158 return MM_ERROR_NONE;
2162 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2164 gboolean disable_overlay = FALSE;
2165 mm_player_t* player = (mm_player_t*) hplayer;
2166 int ret = MM_ERROR_NONE;
2169 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2170 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2171 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2172 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2174 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2175 LOGW("Display control is not supported");
2176 return MM_ERROR_PLAYER_INTERNAL;
2179 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2181 if (audio_only == (bool)disable_overlay) {
2182 LOGE("It's the same with current setting: (%d)", audio_only);
2183 return MM_ERROR_NONE;
2187 LOGE("disable overlay");
2188 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2190 /* release overlay resource */
2191 if (player->video_overlay_resource != NULL) {
2192 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2193 player->video_overlay_resource);
2194 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2195 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
2198 player->video_overlay_resource = NULL;
2201 ret = mm_resource_manager_commit(player->resource_manager);
2202 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2203 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
2207 /* mark video overlay for acquire */
2208 if (player->video_overlay_resource == NULL) {
2209 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2210 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2211 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2212 &player->video_overlay_resource);
2213 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2214 LOGE("could not prepare for video_overlay resource\n");
2219 player->interrupted_by_resource = FALSE;
2220 /* acquire resources for video overlay */
2221 ret = mm_resource_manager_commit(player->resource_manager);
2222 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2223 LOGE("could not acquire resources for video playing\n");
2227 LOGD("enable overlay");
2228 __mmplayer_video_param_set_display_overlay(player);
2229 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2234 return MM_ERROR_NONE;
2238 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2240 mm_player_t* player = (mm_player_t*) hplayer;
2241 gboolean disable_overlay = FALSE;
2245 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2246 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2247 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2248 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2249 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2251 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2252 LOGW("Display control is not supported");
2253 return MM_ERROR_PLAYER_INTERNAL;
2256 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2258 *paudio_only = (bool)(disable_overlay);
2260 LOGD("audio_only : %d", *paudio_only);
2264 return MM_ERROR_NONE;
2268 __mmplayer_gst_element_link_bucket(GList* element_bucket)
2270 GList* bucket = element_bucket;
2271 MMPlayerGstElement* element = NULL;
2272 MMPlayerGstElement* prv_element = NULL;
2273 gint successful_link_count = 0;
2277 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2279 prv_element = (MMPlayerGstElement*)bucket->data;
2280 bucket = bucket->next;
2282 for (; bucket; bucket = bucket->next) {
2283 element = (MMPlayerGstElement*)bucket->data;
2285 if (element && element->gst) {
2286 if (prv_element && prv_element->gst) {
2287 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2288 LOGD("linking [%s] to [%s] success\n",
2289 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2290 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2291 successful_link_count++;
2293 LOGD("linking [%s] to [%s] failed\n",
2294 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2295 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2301 prv_element = element;
2306 return successful_link_count;
2310 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
2312 GList* bucket = element_bucket;
2313 MMPlayerGstElement* element = NULL;
2314 int successful_add_count = 0;
2318 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2319 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2321 for (; bucket; bucket = bucket->next) {
2322 element = (MMPlayerGstElement*)bucket->data;
2324 if (element && element->gst) {
2325 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2326 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
2327 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2328 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2331 successful_add_count++;
2337 return successful_add_count;
2340 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2342 mm_player_t *player = (mm_player_t*) data;
2343 GstCaps *caps = NULL;
2344 GstStructure *str = NULL;
2346 gboolean caps_ret = TRUE;
2350 MMPLAYER_RETURN_IF_FAIL(pad);
2351 MMPLAYER_RETURN_IF_FAIL(unused);
2352 MMPLAYER_RETURN_IF_FAIL(data);
2354 caps = gst_pad_get_current_caps(pad);
2358 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2362 LOGD("name = %s", name);
2364 if (strstr(name, "audio")) {
2365 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2367 if (player->audio_stream_changed_cb) {
2368 LOGE("call the audio stream changed cb");
2369 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2371 } else if (strstr(name, "video")) {
2372 if ((name = gst_structure_get_string(str, "format")))
2373 player->set_mode.video_zc = name[0] == 'S';
2375 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2377 if (player->video_stream_changed_cb) {
2378 LOGE("call the video stream changed cb");
2379 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2382 LOGW("invalid caps info");
2387 gst_caps_unref(caps);
2397 * This function is to create audio pipeline for playing.
2399 * @param player [in] handle of player
2401 * @return This function returns zero on success.
2403 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
2405 /* macro for code readability. just for sinkbin-creation functions */
2406 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2408 x_bin[x_id].id = x_id;\
2409 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2410 if (!x_bin[x_id].gst) {\
2411 LOGE("failed to create %s \n", x_factory);\
2414 if (x_player->ini.set_dump_element_flag)\
2415 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2418 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2422 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
2427 MMPLAYER_RETURN_IF_FAIL(player);
2429 if (player->audio_stream_buff_list) {
2430 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2431 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2434 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2435 __mmplayer_audio_stream_send_data(player, tmp);
2438 g_free(tmp->pcm_data);
2442 g_list_free(player->audio_stream_buff_list);
2443 player->audio_stream_buff_list = NULL;
2450 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
2452 MMPlayerAudioStreamDataType audio_stream = { 0, };
2455 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2457 audio_stream.bitrate = a_buffer->bitrate;
2458 audio_stream.channel = a_buffer->channel;
2459 audio_stream.depth = a_buffer->depth;
2460 audio_stream.is_little_endian = a_buffer->is_little_endian;
2461 audio_stream.channel_mask = a_buffer->channel_mask;
2462 audio_stream.data_size = a_buffer->data_size;
2463 audio_stream.data = a_buffer->pcm_data;
2465 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
2466 player->audio_stream_render_cb(&audio_stream, player->audio_stream_cb_user_param);
2472 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
2474 mm_player_t* player = (mm_player_t*) data;
2479 gint endianness = 0;
2480 guint64 channel_mask = 0;
2481 void *a_data = NULL;
2483 mm_player_audio_stream_buff_t *a_buffer = NULL;
2484 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2488 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2490 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2491 a_data = mapinfo.data;
2492 a_size = mapinfo.size;
2494 GstCaps *caps = gst_pad_get_current_caps(pad);
2495 GstStructure *structure = gst_caps_get_structure(caps, 0);
2497 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2498 gst_structure_get_int(structure, "rate", &rate);
2499 gst_structure_get_int(structure, "channels", &channel);
2500 gst_structure_get_int(structure, "depth", &depth);
2501 gst_structure_get_int(structure, "endianness", &endianness);
2502 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2503 gst_caps_unref(GST_CAPS(caps));
2505 /* In case of the sync is false, use buffer list. *
2506 * The num of buffer list depends on the num of audio channels */
2507 if (player->audio_stream_buff_list) {
2508 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2509 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2511 if (channel_mask == tmp->channel_mask) {
2512 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2513 if (tmp->data_size + a_size < tmp->buff_size) {
2514 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2515 tmp->data_size += a_size;
2517 /* send data to client */
2518 __mmplayer_audio_stream_send_data(player, tmp);
2520 if (a_size > tmp->buff_size) {
2521 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2522 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2523 if (tmp->pcm_data == NULL) {
2524 LOGE("failed to realloc data.");
2527 tmp->buff_size = a_size;
2529 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2530 memcpy(tmp->pcm_data, a_data, a_size);
2531 tmp->data_size = a_size;
2536 LOGE("data is empty in list.");
2542 /* create new audio stream data */
2543 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
2544 if (a_buffer == NULL) {
2545 LOGE("failed to alloc data.");
2548 a_buffer->bitrate = rate;
2549 a_buffer->channel = channel;
2550 a_buffer->depth = depth;
2551 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
2552 a_buffer->channel_mask = channel_mask;
2553 a_buffer->data_size = a_size;
2555 if (!player->audio_stream_sink_sync) {
2556 /* If sync is FALSE, use buffer list to reduce the IPC. */
2557 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2558 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
2559 if (a_buffer->pcm_data == NULL) {
2560 LOGE("failed to alloc data.");
2564 memcpy(a_buffer->pcm_data, a_data, a_size);
2565 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2566 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2568 /* If sync is TRUE, send data directly. */
2569 a_buffer->pcm_data = a_data;
2570 __mmplayer_audio_stream_send_data(player, a_buffer);
2575 gst_buffer_unmap(buffer, &mapinfo);
2580 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2582 mm_player_t* player = (mm_player_t*)data;
2583 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
2584 GstPad* sinkpad = NULL;
2585 GstElement *queue = NULL, *sink = NULL;
2588 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2590 queue = gst_element_factory_make("queue", NULL);
2591 if (queue == NULL) {
2592 LOGD("fail make queue\n");
2596 sink = gst_element_factory_make("fakesink", NULL);
2598 LOGD("fail make fakesink\n");
2602 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2604 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2605 LOGW("failed to link queue & sink\n");
2609 sinkpad = gst_element_get_static_pad(queue, "sink");
2611 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2612 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
2616 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
2618 gst_object_unref(sinkpad);
2619 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
2620 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2622 gst_element_set_state(sink, GST_STATE_PAUSED);
2623 gst_element_set_state(queue, GST_STATE_PAUSED);
2625 __mmplayer_add_signal_connection(player,
2627 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2629 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2636 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
2638 gst_object_unref(GST_OBJECT(queue));
2642 gst_object_unref(GST_OBJECT(sink));
2646 gst_object_unref(GST_OBJECT(sinkpad));
2653 void __mmplayer_gst_set_pulsesink_property(mm_player_t* player, MMHandleType attrs)
2655 #define MAX_PROPS_LEN 128
2656 gint latency_mode = 0;
2657 gchar *stream_type = NULL;
2658 gchar *latency = NULL;
2660 gchar stream_props[MAX_PROPS_LEN] = {0,};
2661 GstStructure *props = NULL;
2664 * It should be set after player creation through attribute.
2665 * But, it can not be changed during playing.
2668 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2670 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
2671 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
2674 LOGE("stream_type is null.");
2676 if (player->sound.focus_id)
2677 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
2678 stream_type, stream_id, player->sound.focus_id);
2680 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
2681 stream_type, stream_id);
2682 props = gst_structure_from_string(stream_props, NULL);
2683 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2684 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].",
2685 stream_type, stream_id, player->sound.focus_id, stream_props);
2686 gst_structure_free(props);
2689 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2691 switch (latency_mode) {
2692 case AUDIO_LATENCY_MODE_LOW:
2693 latency = g_strndup("low", 3);
2695 case AUDIO_LATENCY_MODE_MID:
2696 latency = g_strndup("mid", 3);
2698 case AUDIO_LATENCY_MODE_HIGH:
2699 latency = g_strndup("high", 4);
2703 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2707 LOGD("audiosink property - latency=%s", latency);
2714 void __mmplayer_gst_set_openalsink_property(mm_player_t* player)
2716 MMPlayerGstElement *audiobin = NULL;
2719 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2721 audiobin = player->pipeline->audiobin;
2723 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2724 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2725 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2727 if (player->video360_yaw_radians <= M_PI &&
2728 player->video360_yaw_radians >= -M_PI &&
2729 player->video360_pitch_radians <= M_PI_2 &&
2730 player->video360_pitch_radians >= -M_PI_2) {
2731 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2732 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
2733 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
2734 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2735 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2736 "source-orientation-y", player->video360_metadata.init_view_heading,
2737 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2744 __mmplayer_gst_fill_audio_bucket(mm_player_t *player, GList **bucket)
2746 MMPlayerGstElement *audiobin = NULL;
2747 MMHandleType attrs = 0;
2748 GList *element_bucket = NULL;
2749 GstCaps *acaps = NULL;
2750 GstPad *sink_pad = NULL;
2753 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2754 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2756 audiobin = player->pipeline->audiobin;
2757 attrs = MMPLAYER_GET_ATTRS(player);
2760 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2762 /* replaygain volume */
2763 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2764 if (player->sound.rg_enable)
2765 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2767 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2770 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2772 if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2773 gchar *dst_format = NULL;
2775 int dst_samplerate = 0;
2776 int dst_channels = 0;
2777 GstCaps *caps = NULL;
2778 char *caps_str = NULL;
2780 /* get conf. values */
2781 mm_attrs_multiple_get(player->attrs, NULL,
2782 "pcm_audioformat", &dst_format, &dst_len,
2783 "pcm_extraction_samplerate", &dst_samplerate,
2784 "pcm_extraction_channels", &dst_channels,
2787 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2790 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2791 caps = gst_caps_new_simple("audio/x-raw",
2792 "format", G_TYPE_STRING, dst_format,
2793 "rate", G_TYPE_INT, dst_samplerate,
2794 "channels", G_TYPE_INT, dst_channels,
2797 caps_str = gst_caps_to_string(caps);
2798 LOGD("new caps : %s", caps_str);
2800 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2803 gst_caps_unref(caps);
2804 MMPLAYER_FREEIF(caps_str);
2806 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2808 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2810 /* raw pad handling signal, audiosink will be added after getting signal */
2811 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2812 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2816 /* normal playback */
2819 /* for logical volume control */
2820 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2821 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2823 if (player->sound.mute) {
2824 LOGD("mute enabled");
2825 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2828 /* check if multi-channels */
2829 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
2830 GstPad *srcpad = NULL;
2831 GstCaps *caps = NULL;
2833 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
2834 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
2835 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2836 GstStructure *str = gst_caps_get_structure(caps, 0);
2838 gst_structure_get_int(str, "channels", &channels);
2839 gst_caps_unref(caps);
2841 gst_object_unref(srcpad);
2845 /* audio effect element. if audio effect is enabled */
2846 if ((strcmp(player->ini.audioeffect_element, ""))
2848 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2849 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2851 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2853 if ((!player->bypass_audio_effect)
2854 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2855 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2856 if (!_mmplayer_audio_effect_custom_apply(player))
2857 LOGI("apply audio effect(custom) setting success");
2861 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2862 && (player->set_mode.rich_audio))
2863 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2866 /* create audio sink */
2867 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2868 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2869 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2871 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2872 if (player->is_360_feature_enabled &&
2873 player->is_content_spherical &&
2875 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2876 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2877 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2879 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2881 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2883 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2884 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2885 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2886 gst_caps_unref(acaps);
2888 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2890 player->is_openal_plugin_used = TRUE;
2892 if (player->is_360_feature_enabled && player->is_content_spherical)
2893 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2894 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2897 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2898 (player->videodec_linked && player->ini.use_system_clock)) {
2899 LOGD("system clock will be used.");
2900 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2903 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2904 __mmplayer_gst_set_pulsesink_property(player, attrs);
2905 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2906 __mmplayer_gst_set_openalsink_property(player);
2909 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2910 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2912 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2913 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2914 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2915 gst_object_unref(GST_OBJECT(sink_pad));
2917 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2920 *bucket = element_bucket;
2923 return MM_ERROR_NONE;
2926 g_list_free(element_bucket);
2930 return MM_ERROR_PLAYER_INTERNAL;
2934 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
2936 MMPlayerGstElement *first_element = NULL;
2937 MMPlayerGstElement *audiobin = NULL;
2939 GstPad *ghostpad = NULL;
2940 GList *element_bucket = NULL;
2944 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2947 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2949 LOGE("failed to allocate memory for audiobin");
2950 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2954 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2955 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2956 if (!audiobin[MMPLAYER_A_BIN].gst) {
2957 LOGE("failed to create audiobin");
2962 player->pipeline->audiobin = audiobin;
2964 /* create audio filters and audiosink */
2965 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2968 /* adding created elements to bin */
2969 LOGD("adding created elements to bin");
2970 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2973 /* linking elements in the bucket by added order. */
2974 LOGD("Linking elements in the bucket by added order.");
2975 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2978 /* get first element's sinkpad for creating ghostpad */
2979 first_element = (MMPlayerGstElement *)element_bucket->data;
2980 if (!first_element) {
2981 LOGE("failed to get first elem");
2985 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2987 LOGE("failed to get pad from first element of audiobin");
2991 ghostpad = gst_ghost_pad_new("sink", pad);
2993 LOGE("failed to create ghostpad");
2997 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2998 LOGE("failed to add ghostpad to audiobin");
3002 gst_object_unref(pad);
3004 g_list_free(element_bucket);
3007 return MM_ERROR_NONE;
3010 LOGD("ERROR : releasing audiobin");
3013 gst_object_unref(GST_OBJECT(pad));
3016 gst_object_unref(GST_OBJECT(ghostpad));
3019 g_list_free(element_bucket);
3021 /* release element which are not added to bin */
3022 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3023 /* NOTE : skip bin */
3024 if (audiobin[i].gst) {
3025 GstObject* parent = NULL;
3026 parent = gst_element_get_parent(audiobin[i].gst);
3029 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3030 audiobin[i].gst = NULL;
3032 gst_object_unref(GST_OBJECT(parent));
3036 /* release audiobin with it's childs */
3037 if (audiobin[MMPLAYER_A_BIN].gst)
3038 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3040 MMPLAYER_FREEIF(audiobin);
3042 player->pipeline->audiobin = NULL;
3044 return MM_ERROR_PLAYER_INTERNAL;
3047 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
3049 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3052 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
3054 int ret = MM_ERROR_NONE;
3056 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3057 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3059 MMPLAYER_VIDEO_BO_LOCK(player);
3061 if (player->video_bo_list) {
3062 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3063 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3064 if (tmp && tmp->bo == bo) {
3066 LOGD("release bo %p", bo);
3067 tbm_bo_unref(tmp->bo);
3068 MMPLAYER_VIDEO_BO_UNLOCK(player);
3069 MMPLAYER_VIDEO_BO_SIGNAL(player);
3074 /* hw codec is running or the list was reset for DRC. */
3075 LOGW("there is no bo list.");
3077 MMPLAYER_VIDEO_BO_UNLOCK(player);
3079 LOGW("failed to find bo %p", bo);
3084 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
3089 MMPLAYER_RETURN_IF_FAIL(player);
3091 MMPLAYER_VIDEO_BO_LOCK(player);
3092 if (player->video_bo_list) {
3093 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3094 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3095 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3098 tbm_bo_unref(tmp->bo);
3102 g_list_free(player->video_bo_list);
3103 player->video_bo_list = NULL;
3105 player->video_bo_size = 0;
3106 MMPLAYER_VIDEO_BO_UNLOCK(player);
3113 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
3116 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3117 gboolean ret = TRUE;
3119 /* check DRC, if it is, destroy the prev bo list to create again */
3120 if (player->video_bo_size != size) {
3121 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3122 __mmplayer_video_stream_destroy_bo_list(player);
3123 player->video_bo_size = size;
3126 MMPLAYER_VIDEO_BO_LOCK(player);
3128 if ((!player->video_bo_list) ||
3129 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3131 /* create bo list */
3133 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3135 if (player->video_bo_list) {
3136 /* if bo list did not created all, try it again. */
3137 idx = g_list_length(player->video_bo_list);
3138 LOGD("bo list exist(len: %d)", idx);
3141 for (; idx < player->ini.num_of_video_bo; idx++) {
3142 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
3144 LOGE("Fail to alloc bo_info.");
3147 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3149 LOGE("Fail to tbm_bo_alloc.");
3153 bo_info->used = FALSE;
3154 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3157 /* update video num buffers */
3158 player->video_num_buffers = idx;
3159 if (idx == player->ini.num_of_video_bo)
3160 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3163 MMPLAYER_VIDEO_BO_UNLOCK(player);
3167 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3171 /* get bo from list*/
3172 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3173 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3174 if (tmp && (tmp->used == FALSE)) {
3175 LOGD("found bo %p to use", tmp->bo);
3177 MMPLAYER_VIDEO_BO_UNLOCK(player);
3178 return tbm_bo_ref(tmp->bo);
3182 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3183 MMPLAYER_VIDEO_BO_UNLOCK(player);
3187 if (player->ini.video_bo_timeout <= 0) {
3188 MMPLAYER_VIDEO_BO_WAIT(player);
3190 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
3191 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3198 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3200 mm_player_t* player = (mm_player_t*)data;
3202 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3204 /* send prerolled pkt */
3205 player->video_stream_prerolled = FALSE;
3207 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3209 /* not to send prerolled pkt again */
3210 player->video_stream_prerolled = TRUE;
3214 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3216 mm_player_t* player = (mm_player_t*)data;
3217 MMPlayerVideoStreamDataType *stream = NULL;
3218 GstMemory *mem = NULL;
3221 MMPLAYER_RETURN_IF_FAIL(player);
3222 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3224 if (player->video_stream_prerolled) {
3225 player->video_stream_prerolled = FALSE;
3226 LOGD("skip the prerolled pkt not to send it again");
3230 /* clear stream data structure */
3231 stream = __mmplayer_create_stream_from_pad(pad);
3233 LOGE("failed to alloc stream");
3237 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3239 /* set size and timestamp */
3240 mem = gst_buffer_peek_memory(buffer, 0);
3241 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3242 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3244 /* check zero-copy */
3245 if (player->set_mode.video_zc &&
3246 player->set_mode.media_packet_video_stream &&
3247 gst_is_tizen_memory(mem)) {
3248 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3249 stream->internal_buffer = gst_buffer_ref(buffer);
3250 } else { /* sw codec */
3251 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3254 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3258 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3259 LOGE("failed to send video stream data.");
3266 LOGE("release video stream resource.");
3267 if (gst_is_tizen_memory(mem)) {
3269 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3271 tbm_bo_unref(stream->bo[i]);
3274 /* unref gst buffer */
3275 if (stream->internal_buffer)
3276 gst_buffer_unref(stream->internal_buffer);
3279 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3286 __mmplayer_gst_set_video360_property(mm_player_t *player)
3288 MMPlayerGstElement *videobin = NULL;
3291 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3293 videobin = player->pipeline->videobin;
3295 /* Set spatial media metadata and/or user settings to the element.
3297 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3298 "projection-type", player->video360_metadata.projection_type, NULL);
3300 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3301 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3303 if (player->video360_metadata.full_pano_width_pixels &&
3304 player->video360_metadata.full_pano_height_pixels &&
3305 player->video360_metadata.cropped_area_image_width &&
3306 player->video360_metadata.cropped_area_image_height) {
3307 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3308 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3309 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3310 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3311 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3312 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3313 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3317 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3318 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3319 "horizontal-fov", player->video360_horizontal_fov,
3320 "vertical-fov", player->video360_vertical_fov, NULL);
3323 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3324 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3325 "zoom", 1.0f / player->video360_zoom, NULL);
3328 if (player->video360_yaw_radians <= M_PI &&
3329 player->video360_yaw_radians >= -M_PI &&
3330 player->video360_pitch_radians <= M_PI_2 &&
3331 player->video360_pitch_radians >= -M_PI_2) {
3332 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3333 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
3334 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
3335 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3336 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3337 "pose-yaw", player->video360_metadata.init_view_heading,
3338 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3341 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3342 "passthrough", !player->is_video360_enabled, NULL);
3349 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3351 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3352 GList *element_bucket = NULL;
3355 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3357 /* create video360 filter */
3358 if (player->is_360_feature_enabled && player->is_content_spherical) {
3359 LOGD("create video360 element");
3360 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3361 __mmplayer_gst_set_video360_property(player);
3365 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3366 LOGD("skip creating the videoconv and rotator");
3367 return MM_ERROR_NONE;
3370 /* in case of sw codec & overlay surface type, except 360 playback.
3371 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3372 LOGD("create video converter: %s", video_csc);
3373 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3375 /* set video rotator */
3376 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
3379 *bucket = element_bucket;
3381 return MM_ERROR_NONE;
3383 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3384 g_list_free(element_bucket);
3388 return MM_ERROR_PLAYER_INTERNAL;
3392 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3394 gchar *factory_name = NULL;
3396 switch (surface_type) {
3397 case MM_DISPLAY_SURFACE_OVERLAY:
3398 if (strlen(player->ini.videosink_element_overlay) > 0)
3399 factory_name = player->ini.videosink_element_overlay;
3401 case MM_DISPLAY_SURFACE_NULL:
3402 if (strlen(player->ini.videosink_element_fake) > 0)
3403 factory_name = player->ini.videosink_element_fake;
3405 case MM_DISPLAY_SURFACE_REMOTE:
3406 if (strlen(player->ini.videosink_element_fake) > 0)
3407 factory_name = player->ini.videosink_element_fake;
3410 LOGE("unidentified surface type");
3414 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3415 return factory_name;
3419 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3421 gchar *factory_name = NULL;
3422 MMPlayerGstElement *videobin = NULL;
3426 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3428 videobin = player->pipeline->videobin;
3429 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3431 attrs = MMPLAYER_GET_ATTRS(player);
3433 LOGE("cannot get content attribute");
3434 return MM_ERROR_PLAYER_INTERNAL;
3437 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_REMOTE) {
3440 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3441 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3442 LOGD("OVERLAY: selected videosink is %s", factory_name);
3445 /* support shard memory with S/W codec on HawkP */
3446 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3447 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3448 "use-tbm", use_tbm, NULL);
3452 LOGE("REMOTE : add data probe at videosink");
3453 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3454 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3457 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3459 LOGD("disable last-sample");
3460 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3463 if (player->set_mode.media_packet_video_stream) {
3465 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3466 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE))
3467 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3469 __mmplayer_add_signal_connection(player,
3470 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3471 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3473 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3476 __mmplayer_add_signal_connection(player,
3477 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3478 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3480 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3485 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3486 return MM_ERROR_PLAYER_INTERNAL;
3488 if (videobin[MMPLAYER_V_SINK].gst) {
3489 GstPad *sink_pad = NULL;
3490 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3492 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3493 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3494 gst_object_unref(GST_OBJECT(sink_pad));
3496 LOGE("failed to get sink pad from videosink");
3500 return MM_ERROR_NONE;
3505 * - video overlay surface(arm/x86) : tizenwlsink
3508 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
3511 GList *element_bucket = NULL;
3512 MMPlayerGstElement *first_element = NULL;
3513 MMPlayerGstElement *videobin = NULL;
3514 gchar *videosink_factory_name = NULL;
3517 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3520 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3522 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3524 player->pipeline->videobin = videobin;
3527 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3528 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3529 if (!videobin[MMPLAYER_V_BIN].gst) {
3530 LOGE("failed to create videobin");
3534 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3537 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3538 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3540 /* additional setting for sink plug-in */
3541 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3542 LOGE("failed to set video property");
3546 /* store it as it's sink element */
3547 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3549 /* adding created elements to bin */
3550 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3551 LOGE("failed to add elements");
3555 /* Linking elements in the bucket by added order */
3556 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3557 LOGE("failed to link elements");
3561 /* get first element's sinkpad for creating ghostpad */
3562 first_element = (MMPlayerGstElement *)element_bucket->data;
3563 if (!first_element) {
3564 LOGE("failed to get first element from bucket");
3568 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3570 LOGE("failed to get pad from first element");
3574 /* create ghostpad */
3575 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3576 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3577 LOGE("failed to add ghostpad to videobin");
3580 gst_object_unref(pad);
3582 /* done. free allocated variables */
3583 g_list_free(element_bucket);
3587 return MM_ERROR_NONE;
3590 LOGE("ERROR : releasing videobin");
3591 g_list_free(element_bucket);
3594 gst_object_unref(GST_OBJECT(pad));
3596 /* release videobin with it's childs */
3597 if (videobin[MMPLAYER_V_BIN].gst)
3598 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3600 MMPLAYER_FREEIF(videobin);
3601 player->pipeline->videobin = NULL;
3603 return MM_ERROR_PLAYER_INTERNAL;
3606 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
3608 GList *element_bucket = NULL;
3609 MMPlayerGstElement *textbin = player->pipeline->textbin;
3611 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3612 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3613 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3614 "signal-handoffs", FALSE,
3617 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3618 __mmplayer_add_signal_connection(player,
3619 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3620 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3622 G_CALLBACK(__mmplayer_update_subtitle),
3625 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3626 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3628 if (!player->play_subtitle) {
3629 LOGD("add textbin sink as sink element of whole pipeline.\n");
3630 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3633 /* adding created elements to bin */
3634 LOGD("adding created elements to bin\n");
3635 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3636 LOGE("failed to add elements\n");
3640 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3641 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3642 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3644 /* linking elements in the bucket by added order. */
3645 LOGD("Linking elements in the bucket by added order.\n");
3646 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3647 LOGE("failed to link elements\n");
3651 /* done. free allocated variables */
3652 g_list_free(element_bucket);
3654 if (textbin[MMPLAYER_T_QUEUE].gst) {
3656 GstPad *ghostpad = NULL;
3658 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3660 LOGE("failed to get sink pad of text queue");
3664 ghostpad = gst_ghost_pad_new("text_sink", pad);
3665 gst_object_unref(pad);
3668 LOGE("failed to create ghostpad of textbin\n");
3672 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3673 LOGE("failed to add ghostpad to textbin\n");
3674 gst_object_unref(ghostpad);
3679 return MM_ERROR_NONE;
3682 g_list_free(element_bucket);
3684 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3685 LOGE("remove textbin sink from sink list");
3686 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3689 /* release element at __mmplayer_gst_create_text_sink_bin */
3690 return MM_ERROR_PLAYER_INTERNAL;
3693 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
3695 MMPlayerGstElement *textbin = NULL;
3696 GList *element_bucket = NULL;
3697 int surface_type = 0;
3702 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3705 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3707 LOGE("failed to allocate memory for textbin\n");
3708 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3712 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3713 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3714 if (!textbin[MMPLAYER_T_BIN].gst) {
3715 LOGE("failed to create textbin\n");
3720 player->pipeline->textbin = textbin;
3723 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3724 LOGD("surface type for subtitle : %d", surface_type);
3725 switch (surface_type) {
3726 case MM_DISPLAY_SURFACE_OVERLAY:
3727 case MM_DISPLAY_SURFACE_NULL:
3728 case MM_DISPLAY_SURFACE_REMOTE:
3729 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3730 LOGE("failed to make plain text elements\n");
3741 return MM_ERROR_NONE;
3745 LOGD("ERROR : releasing textbin\n");
3747 g_list_free(element_bucket);
3749 /* release signal */
3750 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3752 /* release element which are not added to bin */
3753 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3754 /* NOTE : skip bin */
3755 if (textbin[i].gst) {
3756 GstObject* parent = NULL;
3757 parent = gst_element_get_parent(textbin[i].gst);
3760 gst_object_unref(GST_OBJECT(textbin[i].gst));
3761 textbin[i].gst = NULL;
3763 gst_object_unref(GST_OBJECT(parent));
3768 /* release textbin with it's childs */
3769 if (textbin[MMPLAYER_T_BIN].gst)
3770 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3772 MMPLAYER_FREEIF(player->pipeline->textbin);
3773 player->pipeline->textbin = NULL;
3776 return MM_ERROR_PLAYER_INTERNAL;
3781 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
3783 MMPlayerGstElement* mainbin = NULL;
3784 MMPlayerGstElement* textbin = NULL;
3785 MMHandleType attrs = 0;
3786 GstElement *subsrc = NULL;
3787 GstElement *subparse = NULL;
3788 gchar *subtitle_uri = NULL;
3789 const gchar *charset = NULL;
3795 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3797 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3799 mainbin = player->pipeline->mainbin;
3801 attrs = MMPLAYER_GET_ATTRS(player);
3803 LOGE("cannot get content attribute\n");
3804 return MM_ERROR_PLAYER_INTERNAL;
3807 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3808 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3809 LOGE("subtitle uri is not proper filepath.\n");
3810 return MM_ERROR_PLAYER_INVALID_URI;
3813 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3814 LOGE("failed to get storage info of subtitle path");
3815 return MM_ERROR_PLAYER_INVALID_URI;
3818 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
3820 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3821 player->subtitle_language_list = NULL;
3822 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3824 /* create the subtitle source */
3825 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3827 LOGE("failed to create filesrc element\n");
3830 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3832 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3833 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3835 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3836 LOGW("failed to add queue\n");
3837 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3838 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3839 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3844 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3846 LOGE("failed to create subparse element\n");
3850 charset = util_get_charset(subtitle_uri);
3852 LOGD("detected charset is %s\n", charset);
3853 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3856 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3857 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3859 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3860 LOGW("failed to add subparse\n");
3861 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3862 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3863 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3867 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3868 LOGW("failed to link subsrc and subparse\n");
3872 player->play_subtitle = TRUE;
3873 player->adjust_subtitle_pos = 0;
3875 LOGD("play subtitle using subtitle file\n");
3877 if (player->pipeline->textbin == NULL) {
3878 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3879 LOGE("failed to create text sink bin. continuing without text\n");
3883 textbin = player->pipeline->textbin;
3885 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3886 LOGW("failed to add textbin\n");
3888 /* release signal */
3889 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3891 /* release textbin with it's childs */
3892 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3893 MMPLAYER_FREEIF(player->pipeline->textbin);
3894 player->pipeline->textbin = textbin = NULL;
3898 LOGD("link text input selector and textbin ghost pad");
3900 player->textsink_linked = 1;
3901 player->external_text_idx = 0;
3902 LOGI("player->textsink_linked set to 1\n");
3904 textbin = player->pipeline->textbin;
3905 LOGD("text bin has been created. reuse it.");
3906 player->external_text_idx = 1;
3909 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3910 LOGW("failed to link subparse and textbin\n");
3914 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3916 LOGE("failed to get sink pad from textsink to probe data");
3920 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3921 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3923 gst_object_unref(pad);
3926 /* create dot. for debugging */
3927 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3930 return MM_ERROR_NONE;
3933 /* release text pipeline resource */
3934 player->textsink_linked = 0;
3936 /* release signal */
3937 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3939 if (player->pipeline->textbin) {
3940 LOGE("remove textbin");
3942 /* release textbin with it's childs */
3943 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3944 MMPLAYER_FREEIF(player->pipeline->textbin);
3945 player->pipeline->textbin = NULL;
3949 /* release subtitle elem */
3950 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3951 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3953 return MM_ERROR_PLAYER_INTERNAL;
3957 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3959 mm_player_t* player = (mm_player_t*) data;
3960 MMMessageParamType msg = {0, };
3961 GstClockTime duration = 0;
3962 gpointer text = NULL;
3963 guint text_size = 0;
3964 gboolean ret = TRUE;
3965 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3969 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3970 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3972 if (player->is_subtitle_force_drop) {
3973 LOGW("subtitle is dropped forcedly.");
3977 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3978 text = mapinfo.data;
3979 text_size = mapinfo.size;
3980 duration = GST_BUFFER_DURATION(buffer);
3982 if (player->set_mode.subtitle_off) {
3983 LOGD("subtitle is OFF.\n");
3987 if (!text || (text_size == 0)) {
3988 LOGD("There is no subtitle to be displayed.\n");
3992 msg.data = (void *) text;
3993 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3995 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
3997 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3998 gst_buffer_unmap(buffer, &mapinfo);
4005 static GstPadProbeReturn
4006 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4008 mm_player_t *player = (mm_player_t *) u_data;
4009 GstClockTime cur_timestamp = 0;
4010 gint64 adjusted_timestamp = 0;
4011 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4013 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4015 if (player->set_mode.subtitle_off) {
4016 LOGD("subtitle is OFF.\n");
4020 if (player->adjust_subtitle_pos == 0) {
4021 LOGD("nothing to do");
4025 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4026 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4028 if (adjusted_timestamp < 0) {
4029 LOGD("adjusted_timestamp under zero");
4034 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4035 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4036 GST_TIME_ARGS(cur_timestamp),
4037 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4039 return GST_PAD_PROBE_OK;
4041 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
4045 /* check player and subtitlebin are created */
4046 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4047 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4049 if (position == 0) {
4050 LOGD("nothing to do\n");
4052 return MM_ERROR_NONE;
4056 case MM_PLAYER_POS_FORMAT_TIME:
4058 /* check current postion */
4059 player->adjust_subtitle_pos = position;
4061 LOGD("save adjust_subtitle_pos in player") ;
4067 LOGW("invalid format.\n");
4069 return MM_ERROR_INVALID_ARGUMENT;
4075 return MM_ERROR_NONE;
4079 * This function is to create audio or video pipeline for playing.
4081 * @param player [in] handle of player
4083 * @return This function returns zero on success.
4088 __mmplayer_gst_create_pipeline(mm_player_t* player)
4090 int ret = MM_ERROR_NONE;
4091 MMPlayerGstElement *mainbin = NULL;
4092 MMHandleType attrs = 0;
4093 gint mode = MM_PLAYER_PD_MODE_NONE;
4096 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4098 /* get profile attribute */
4099 attrs = MMPLAYER_GET_ATTRS(player);
4101 LOGE("failed to get content attribute");
4105 /* create pipeline handles */
4106 if (player->pipeline) {
4107 LOGE("pipeline should be released before create new one");
4111 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
4112 if (player->pipeline == NULL)
4115 /* create mainbin */
4116 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
4117 if (mainbin == NULL)
4120 /* create pipeline */
4121 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4122 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4123 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4124 LOGE("failed to create pipeline");
4129 player->pipeline->mainbin = mainbin;
4132 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
4133 player->pd_mode = mode;
4135 /* create the source and decoder elements */
4136 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4137 ret = __mmplayer_gst_build_es_pipeline(player);
4138 } else if (MMPLAYER_IS_HTTP_STREAMING(player) && MMPLAYER_IS_HTTP_PD(player)) {
4139 ret = __mmplayer_gst_build_pd_pipeline(player);
4141 ret = __mmplayer_gst_build_pipeline(player);
4144 if (ret != MM_ERROR_NONE) {
4145 LOGE("failed to create some elements");
4149 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4150 if (__mmplayer_check_subtitle(player)) {
4151 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE)
4152 LOGE("failed to create text pipeline");
4156 ret = __mmplayer_gst_add_bus_watch(player);
4157 if (ret != MM_ERROR_NONE) {
4158 LOGE("failed to add bus watch");
4163 return MM_ERROR_NONE;
4166 __mmplayer_gst_destroy_pipeline(player);
4167 return MM_ERROR_PLAYER_INTERNAL;
4171 __mmplayer_reset_gapless_state(mm_player_t* player)
4174 MMPLAYER_RETURN_IF_FAIL(player
4176 && player->pipeline->audiobin
4177 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4179 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
4186 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
4189 int ret = MM_ERROR_NONE;
4193 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4195 /* cleanup stuffs */
4196 MMPLAYER_FREEIF(player->type);
4197 player->have_dynamic_pad = FALSE;
4198 player->no_more_pad = FALSE;
4199 player->num_dynamic_pad = 0;
4200 player->demux_pad_index = 0;
4201 player->video_hub_download_mode = 0;
4203 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4204 player->subtitle_language_list = NULL;
4205 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4207 __mmplayer_reset_gapless_state(player);
4209 if (player->streamer) {
4210 __mm_player_streaming_deinitialize(player->streamer);
4211 __mm_player_streaming_destroy(player->streamer);
4212 player->streamer = NULL;
4215 /* cleanup unlinked mime type */
4216 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4217 MMPLAYER_FREEIF(player->unlinked_video_mime);
4218 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4220 /* cleanup running stuffs */
4221 __mmplayer_cancel_eos_timer(player);
4223 /* cleanup gst stuffs */
4224 if (player->pipeline) {
4225 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
4226 GstTagList* tag_list = player->pipeline->tag_list;
4228 /* first we need to disconnect all signal hander */
4229 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4232 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4233 MMPlayerGstElement* videobin = player->pipeline->videobin;
4234 MMPlayerGstElement* textbin = player->pipeline->textbin;
4235 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4236 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4237 gst_object_unref(bus);
4239 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4240 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4241 if (ret != MM_ERROR_NONE) {
4242 LOGE("fail to change state to NULL\n");
4243 return MM_ERROR_PLAYER_INTERNAL;
4246 LOGW("succeeded in changing state to NULL\n");
4248 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4251 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4252 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4254 /* free avsysaudiosink
4255 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4256 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4258 MMPLAYER_FREEIF(audiobin);
4259 MMPLAYER_FREEIF(videobin);
4260 MMPLAYER_FREEIF(textbin);
4261 MMPLAYER_FREEIF(mainbin);
4265 gst_tag_list_free(tag_list);
4267 MMPLAYER_FREEIF(player->pipeline);
4269 MMPLAYER_FREEIF(player->album_art);
4271 if (player->v_stream_caps) {
4272 gst_caps_unref(player->v_stream_caps);
4273 player->v_stream_caps = NULL;
4275 if (player->a_stream_caps) {
4276 gst_caps_unref(player->a_stream_caps);
4277 player->a_stream_caps = NULL;
4280 if (player->s_stream_caps) {
4281 gst_caps_unref(player->s_stream_caps);
4282 player->s_stream_caps = NULL;
4284 __mmplayer_track_destroy(player);
4286 if (player->sink_elements)
4287 g_list_free(player->sink_elements);
4288 player->sink_elements = NULL;
4290 if (player->bufmgr) {
4291 tbm_bufmgr_deinit(player->bufmgr);
4292 player->bufmgr = NULL;
4295 LOGW("finished destroy pipeline\n");
4302 static int __mmplayer_gst_realize(mm_player_t* player)
4305 int ret = MM_ERROR_NONE;
4309 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4311 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4313 ret = __mmplayer_gst_create_pipeline(player);
4315 LOGE("failed to create pipeline\n");
4319 /* set pipeline state to READY */
4320 /* NOTE : state change to READY must be performed sync. */
4321 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4322 ret = __mmplayer_gst_set_state(player,
4323 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4325 if (ret != MM_ERROR_NONE) {
4326 /* return error if failed to set state */
4327 LOGE("failed to set READY state");
4331 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4333 /* create dot before error-return. for debugging */
4334 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4341 static int __mmplayer_gst_unrealize(mm_player_t* player)
4343 int ret = MM_ERROR_NONE;
4347 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4349 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4350 MMPLAYER_PRINT_STATE(player);
4352 /* release miscellaneous information */
4353 __mmplayer_release_misc(player);
4355 /* destroy pipeline */
4356 ret = __mmplayer_gst_destroy_pipeline(player);
4357 if (ret != MM_ERROR_NONE) {
4358 LOGE("failed to destory pipeline\n");
4362 /* release miscellaneous information.
4363 these info needs to be released after pipeline is destroyed. */
4364 __mmplayer_release_misc_post(player);
4366 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4374 __mmplayer_gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
4379 LOGW("set_message_callback is called with invalid player handle\n");
4380 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4383 player->msg_cb = callback;
4384 player->msg_cb_param = user_param;
4386 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
4390 return MM_ERROR_NONE;
4393 int __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
4395 int ret = MM_ERROR_NONE;
4400 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
4401 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
4402 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
4404 memset(data, 0, sizeof(MMPlayerParseProfile));
4406 if (strstr(uri, "es_buff://")) {
4407 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4408 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4409 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4410 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4412 tmp = g_ascii_strdown(uri, strlen(uri));
4413 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4414 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4416 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4418 } else if (strstr(uri, "mms://")) {
4419 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4420 } else if ((path = strstr(uri, "mem://"))) {
4421 ret = __mmplayer_set_mem_uri(data, path, param);
4423 ret = __mmplayer_set_file_uri(data, uri);
4426 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4427 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4428 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4429 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4431 /* dump parse result */
4432 SECURE_LOGW("incoming uri : %s\n", uri);
4433 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
4434 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4442 __mmplayer_can_do_interrupt(mm_player_t *player)
4444 if (!player || !player->pipeline || !player->attrs) {
4445 LOGW("not initialized");
4449 if (player->audio_stream_render_cb) {
4450 LOGW("not support in pcm extraction mode");
4454 /* check if seeking */
4455 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4456 MMMessageParamType msg_param;
4457 memset(&msg_param, 0, sizeof(MMMessageParamType));
4458 msg_param.code = MM_ERROR_PLAYER_SEEK;
4459 player->seek_state = MMPLAYER_SEEK_NONE;
4460 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4464 /* check other thread */
4465 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4466 LOGW("locked already, cmd state : %d", player->cmd);
4468 /* check application command */
4469 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4470 LOGW("playing.. should wait cmd lock then, will be interrupted");
4472 /* lock will be released at mrp_resource_release_cb() */
4473 MMPLAYER_CMD_LOCK(player);
4476 LOGW("nothing to do");
4479 LOGW("can interrupt immediately");
4483 FAILED: /* with CMD UNLOCKED */
4486 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4491 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4494 mm_player_t *player = NULL;
4498 if (user_data == NULL) {
4499 LOGE("- user_data is null\n");
4502 player = (mm_player_t *)user_data;
4504 /* do something to release resource here.
4505 * player stop and interrupt forwarding */
4506 if (!__mmplayer_can_do_interrupt(player)) {
4507 LOGW("no need to interrupt, so leave");
4509 MMMessageParamType msg = {0, };
4512 player->interrupted_by_resource = TRUE;
4514 /* get last play position */
4515 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4516 LOGW("failed to get play position.");
4518 msg.union_type = MM_MSG_UNION_TIME;
4519 msg.time.elapsed = pos;
4520 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4522 LOGD("video resource conflict so, resource will be freed by unrealizing");
4523 if (_mmplayer_unrealize((MMHandleType)player))
4524 LOGW("failed to unrealize");
4526 /* lock is called in __mmplayer_can_do_interrupt() */
4527 MMPLAYER_CMD_UNLOCK(player);
4530 if (res == player->video_overlay_resource)
4531 player->video_overlay_resource = FALSE;
4533 player->video_decoder_resource = FALSE;
4541 __mmplayer_initialize_video_roi(mm_player_t *player)
4543 player->video_roi.scale_x = 0.0;
4544 player->video_roi.scale_y = 0.0;
4545 player->video_roi.scale_width = 1.0;
4546 player->video_roi.scale_height = 1.0;
4550 _mmplayer_create_player(MMHandleType handle)
4552 int ret = MM_ERROR_PLAYER_INTERNAL;
4553 bool enabled = false;
4555 mm_player_t* player = MM_PLAYER_CAST(handle);
4559 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4561 /* initialize player state */
4562 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4563 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4564 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4565 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4567 /* check current state */
4568 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4570 /* construct attributes */
4571 player->attrs = _mmplayer_construct_attribute(handle);
4573 if (!player->attrs) {
4574 LOGE("Failed to construct attributes\n");
4578 /* initialize gstreamer with configured parameter */
4579 if (!__mmplayer_init_gstreamer(player)) {
4580 LOGE("Initializing gstreamer failed\n");
4581 _mmplayer_deconstruct_attribute(handle);
4585 /* create lock. note that g_tread_init() has already called in gst_init() */
4586 g_mutex_init(&player->fsink_lock);
4588 /* create update tag lock */
4589 g_mutex_init(&player->update_tag_lock);
4591 /* create gapless play mutex */
4592 g_mutex_init(&player->gapless_play_thread_mutex);
4594 /* create gapless play cond */
4595 g_cond_init(&player->gapless_play_thread_cond);
4597 /* create gapless play thread */
4598 player->gapless_play_thread =
4599 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4600 if (!player->gapless_play_thread) {
4601 LOGE("failed to create gapless play thread");
4602 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4603 g_mutex_clear(&player->gapless_play_thread_mutex);
4604 g_cond_clear(&player->gapless_play_thread_cond);
4608 player->bus_msg_q = g_queue_new();
4609 if (!player->bus_msg_q) {
4610 LOGE("failed to create queue for bus_msg");
4611 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4615 ret = _mmplayer_initialize_video_capture(player);
4616 if (ret != MM_ERROR_NONE) {
4617 LOGE("failed to initialize video capture\n");
4621 /* initialize resource manager */
4622 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
4623 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
4624 &player->resource_manager)) {
4625 LOGE("failed to initialize resource manager\n");
4626 ret = MM_ERROR_PLAYER_INTERNAL;
4630 if (MMPLAYER_IS_HTTP_PD(player)) {
4631 player->pd_downloader = NULL;
4632 player->pd_file_save_path = NULL;
4635 /* create video bo lock and cond */
4636 g_mutex_init(&player->video_bo_mutex);
4637 g_cond_init(&player->video_bo_cond);
4639 /* create media stream callback mutex */
4640 g_mutex_init(&player->media_stream_cb_lock);
4642 /* create subtitle info lock and cond */
4643 g_mutex_init(&player->subtitle_info_mutex);
4644 g_cond_init(&player->subtitle_info_cond);
4646 player->streaming_type = STREAMING_SERVICE_NONE;
4648 /* give default value of audio effect setting */
4649 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4650 player->sound.rg_enable = false;
4651 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4653 player->play_subtitle = FALSE;
4654 player->has_closed_caption = FALSE;
4655 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4656 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4657 player->pending_resume = FALSE;
4658 if (player->ini.dump_element_keyword[0][0] == '\0')
4659 player->ini.set_dump_element_flag = FALSE;
4661 player->ini.set_dump_element_flag = TRUE;
4663 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4664 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4665 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4667 /* Set video360 settings to their defaults for just-created player.
4670 player->is_360_feature_enabled = FALSE;
4671 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4672 LOGI("spherical feature info: %d", enabled);
4674 player->is_360_feature_enabled = TRUE;
4676 LOGE("failed to get spherical feature info");
4679 player->is_content_spherical = FALSE;
4680 player->is_video360_enabled = TRUE;
4681 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4682 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4683 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4684 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4685 player->video360_zoom = 1.0f;
4686 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4687 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4689 __mmplayer_initialize_video_roi(player);
4691 /* set player state to null */
4692 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4693 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4695 return MM_ERROR_NONE;
4699 g_mutex_clear(&player->fsink_lock);
4701 /* free update tag lock */
4702 g_mutex_clear(&player->update_tag_lock);
4704 g_queue_free(player->bus_msg_q);
4706 /* free gapless play thread */
4707 if (player->gapless_play_thread) {
4708 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4709 player->gapless_play_thread_exit = TRUE;
4710 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4711 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4713 g_thread_join(player->gapless_play_thread);
4714 player->gapless_play_thread = NULL;
4716 g_mutex_clear(&player->gapless_play_thread_mutex);
4717 g_cond_clear(&player->gapless_play_thread_cond);
4720 /* release attributes */
4721 _mmplayer_deconstruct_attribute(handle);
4729 __mmplayer_init_gstreamer(mm_player_t* player)
4731 static gboolean initialized = FALSE;
4732 static const int max_argc = 50;
4734 gchar** argv = NULL;
4735 gchar** argv2 = NULL;
4741 LOGD("gstreamer already initialized.\n");
4746 argc = malloc(sizeof(int));
4747 argv = malloc(sizeof(gchar*) * max_argc);
4748 argv2 = malloc(sizeof(gchar*) * max_argc);
4750 if (!argc || !argv || !argv2)
4753 memset(argv, 0, sizeof(gchar*) * max_argc);
4754 memset(argv2, 0, sizeof(gchar*) * max_argc);
4758 argv[0] = g_strdup("mmplayer");
4761 for (i = 0; i < 5; i++) {
4762 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4763 if (strlen(player->ini.gst_param[i]) > 0) {
4764 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4769 /* we would not do fork for scanning plugins */
4770 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4773 /* check disable registry scan */
4774 if (player->ini.skip_rescan) {
4775 argv[*argc] = g_strdup("--gst-disable-registry-update");
4779 /* check disable segtrap */
4780 if (player->ini.disable_segtrap) {
4781 argv[*argc] = g_strdup("--gst-disable-segtrap");
4785 LOGD("initializing gstreamer with following parameter\n");
4786 LOGD("argc : %d\n", *argc);
4789 for (i = 0; i < arg_count; i++) {
4791 LOGD("argv[%d] : %s\n", i, argv2[i]);
4794 /* initializing gstreamer */
4795 if (!gst_init_check(argc, &argv, &err)) {
4796 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
4803 for (i = 0; i < arg_count; i++) {
4804 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
4805 MMPLAYER_FREEIF(argv2[i]);
4808 MMPLAYER_FREEIF(argv);
4809 MMPLAYER_FREEIF(argv2);
4810 MMPLAYER_FREEIF(argc);
4820 for (i = 0; i < arg_count; i++) {
4821 LOGD("free[%d] : %s\n", i, argv2[i]);
4822 MMPLAYER_FREEIF(argv2[i]);
4825 MMPLAYER_FREEIF(argv);
4826 MMPLAYER_FREEIF(argv2);
4827 MMPLAYER_FREEIF(argc);
4833 __mmplayer_destroy_streaming_ext(mm_player_t* player)
4835 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4837 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
4838 _mmplayer_destroy_pd_downloader((MMHandleType)player);
4839 MMPLAYER_FREEIF(player->pd_file_save_path);
4842 return MM_ERROR_NONE;
4846 __mmplayer_check_async_state_transition(mm_player_t* player)
4848 GstState element_state = GST_STATE_VOID_PENDING;
4849 GstState element_pending_state = GST_STATE_VOID_PENDING;
4850 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4851 GstElement * element = NULL;
4852 gboolean async = FALSE;
4854 /* check player handle */
4855 MMPLAYER_RETURN_IF_FAIL(player &&
4857 player->pipeline->mainbin &&
4858 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4861 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4863 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4864 LOGD("don't need to check the pipeline state");
4868 MMPLAYER_PRINT_STATE(player);
4870 /* wait for state transition */
4871 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4872 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
4874 if (ret == GST_STATE_CHANGE_FAILURE) {
4875 LOGE(" [%s] state : %s pending : %s \n",
4876 GST_ELEMENT_NAME(element),
4877 gst_element_state_get_name(element_state),
4878 gst_element_state_get_name(element_pending_state));
4880 /* dump state of all element */
4881 __mmplayer_dump_pipeline_state(player);
4886 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
4891 _mmplayer_destroy(MMHandleType handle)
4893 mm_player_t* player = MM_PLAYER_CAST(handle);
4897 /* check player handle */
4898 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4900 /* destroy can called at anytime */
4901 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4903 /* check async state transition */
4904 __mmplayer_check_async_state_transition(player);
4906 __mmplayer_destroy_streaming_ext(player);
4908 /* release gapless play thread */
4909 if (player->gapless_play_thread) {
4910 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4911 player->gapless_play_thread_exit = TRUE;
4912 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4913 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4915 LOGD("waitting for gapless play thread exit\n");
4916 g_thread_join(player->gapless_play_thread);
4917 g_mutex_clear(&player->gapless_play_thread_mutex);
4918 g_cond_clear(&player->gapless_play_thread_cond);
4919 LOGD("gapless play thread released\n");
4922 _mmplayer_release_video_capture(player);
4924 /* de-initialize resource manager */
4925 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4926 player->resource_manager))
4927 LOGE("failed to deinitialize resource manager\n");
4929 /* release pipeline */
4930 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4931 LOGE("failed to destory pipeline\n");
4932 return MM_ERROR_PLAYER_INTERNAL;
4935 g_queue_free(player->bus_msg_q);
4937 /* release subtitle info lock and cond */
4938 g_mutex_clear(&player->subtitle_info_mutex);
4939 g_cond_clear(&player->subtitle_info_cond);
4941 __mmplayer_release_dump_list(player->dump_list);
4943 /* release miscellaneous information */
4944 __mmplayer_release_misc(player);
4946 /* release miscellaneous information.
4947 these info needs to be released after pipeline is destroyed. */
4948 __mmplayer_release_misc_post(player);
4950 /* release attributes */
4951 _mmplayer_deconstruct_attribute(handle);
4954 g_mutex_clear(&player->fsink_lock);
4957 g_mutex_clear(&player->update_tag_lock);
4959 /* release video bo lock and cond */
4960 g_mutex_clear(&player->video_bo_mutex);
4961 g_cond_clear(&player->video_bo_cond);
4963 /* release media stream callback lock */
4964 g_mutex_clear(&player->media_stream_cb_lock);
4968 return MM_ERROR_NONE;
4972 __mmplayer_realize_streaming_ext(mm_player_t* player)
4974 int ret = MM_ERROR_NONE;
4977 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4979 if (MMPLAYER_IS_HTTP_PD(player)) {
4980 gboolean bret = FALSE;
4982 player->pd_downloader = _mmplayer_create_pd_downloader();
4983 if (!player->pd_downloader) {
4984 LOGE("Unable to create PD Downloader...");
4985 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
4988 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
4990 if (FALSE == bret) {
4991 LOGE("Unable to create PD Downloader...");
4992 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
5001 _mmplayer_realize(MMHandleType hplayer)
5003 mm_player_t* player = (mm_player_t*)hplayer;
5006 MMHandleType attrs = 0;
5007 int ret = MM_ERROR_NONE;
5011 /* check player handle */
5012 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5014 /* check current state */
5015 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5017 attrs = MMPLAYER_GET_ATTRS(player);
5019 LOGE("fail to get attributes.\n");
5020 return MM_ERROR_PLAYER_INTERNAL;
5022 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5023 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5025 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5026 ret = __mmplayer_parse_profile((const char*)uri, param, &player->profile);
5028 if (ret != MM_ERROR_NONE) {
5029 LOGE("failed to parse profile\n");
5034 if (uri && (strstr(uri, "es_buff://"))) {
5035 if (strstr(uri, "es_buff://push_mode"))
5036 player->es_player_push_mode = TRUE;
5038 player->es_player_push_mode = FALSE;
5041 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5042 LOGW("mms protocol is not supported format.\n");
5043 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5046 if (MMPLAYER_IS_HTTP_PD(player))
5047 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_PD_STATE_CHANGE_TIME;
5048 else if (MMPLAYER_IS_STREAMING(player))
5049 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5051 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5053 player->smooth_streaming = FALSE;
5054 player->videodec_linked = 0;
5055 player->videosink_linked = 0;
5056 player->audiodec_linked = 0;
5057 player->audiosink_linked = 0;
5058 player->textsink_linked = 0;
5059 player->is_external_subtitle_present = FALSE;
5060 player->is_external_subtitle_added_now = FALSE;
5061 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5062 player->video360_metadata.is_spherical = -1;
5063 player->is_openal_plugin_used = FALSE;
5064 player->demux_pad_index = 0;
5065 player->subtitle_language_list = NULL;
5066 player->is_subtitle_force_drop = FALSE;
5067 player->last_multiwin_status = FALSE;
5069 __mmplayer_track_initialize(player);
5070 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5072 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5073 player->streamer = __mm_player_streaming_create();
5074 __mm_player_streaming_initialize(player->streamer);
5077 /* realize pipeline */
5078 ret = __mmplayer_gst_realize(player);
5079 if (ret != MM_ERROR_NONE)
5080 LOGE("fail to realize the player.\n");
5082 ret = __mmplayer_realize_streaming_ext(player);
5084 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5092 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
5095 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5097 /* destroy can called at anytime */
5098 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
5099 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
5102 return MM_ERROR_NONE;
5106 _mmplayer_unrealize(MMHandleType hplayer)
5108 mm_player_t* player = (mm_player_t*)hplayer;
5109 int ret = MM_ERROR_NONE;
5113 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5115 MMPLAYER_CMD_UNLOCK(player);
5116 /* destroy the gst bus msg thread which is created during realize.
5117 this funct have to be called before getting cmd lock. */
5118 __mmplayer_bus_msg_thread_destroy(player);
5119 MMPLAYER_CMD_LOCK(player);
5121 /* check current state */
5122 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5124 /* check async state transition */
5125 __mmplayer_check_async_state_transition(player);
5127 __mmplayer_unrealize_streaming_ext(player);
5129 /* unrealize pipeline */
5130 ret = __mmplayer_gst_unrealize(player);
5132 /* set asm stop if success */
5133 if (MM_ERROR_NONE == ret) {
5134 if (!player->interrupted_by_resource) {
5135 if (player->video_decoder_resource != NULL) {
5136 ret = mm_resource_manager_mark_for_release(player->resource_manager,
5137 player->video_decoder_resource);
5138 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5139 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
5141 player->video_decoder_resource = NULL;
5144 if (player->video_overlay_resource != NULL) {
5145 ret = mm_resource_manager_mark_for_release(player->resource_manager,
5146 player->video_overlay_resource);
5147 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5148 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
5150 player->video_overlay_resource = NULL;
5153 ret = mm_resource_manager_commit(player->resource_manager);
5154 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5155 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
5158 LOGE("failed and don't change asm state to stop");
5166 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5168 mm_player_t* player = (mm_player_t*)hplayer;
5170 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5172 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5176 _mmplayer_get_state(MMHandleType hplayer, int* state)
5178 mm_player_t *player = (mm_player_t*)hplayer;
5180 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5182 *state = MMPLAYER_CURRENT_STATE(player);
5184 return MM_ERROR_NONE;
5189 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
5191 mm_player_t* player = (mm_player_t*) hplayer;
5192 GstElement* vol_element = NULL;
5197 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5199 LOGD("volume [L]=%f:[R]=%f\n",
5200 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
5202 /* invalid factor range or not */
5203 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
5204 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
5205 LOGE("Invalid factor!(valid factor:0~1.0)\n");
5206 return MM_ERROR_INVALID_ARGUMENT;
5210 /* not support to set other value into each channel */
5211 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
5212 return MM_ERROR_INVALID_ARGUMENT;
5214 /* Save volume to handle. Currently the first array element will be saved. */
5215 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
5217 /* check pipeline handle */
5218 if (!player->pipeline || !player->pipeline->audiobin) {
5219 LOGD("audiobin is not created yet\n");
5220 LOGD("but, current stored volume will be set when it's created.\n");
5222 /* NOTE : stored volume will be used in create_audiobin
5223 * returning MM_ERROR_NONE here makes application to able to
5224 * set volume at anytime.
5226 return MM_ERROR_NONE;
5229 /* setting volume to volume element */
5230 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5233 LOGD("volume is set [%f]\n", player->sound.volume);
5234 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5239 return MM_ERROR_NONE;
5244 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
5246 mm_player_t* player = (mm_player_t*) hplayer;
5251 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5252 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5254 /* returning stored volume */
5255 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
5256 volume->level[i] = player->sound.volume;
5260 return MM_ERROR_NONE;
5264 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5266 mm_player_t* player = (mm_player_t*) hplayer;
5267 GstElement* vol_element = NULL;
5271 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5273 /* mute value shoud 0 or 1 */
5274 if (mute != 0 && mute != 1) {
5275 LOGE("bad mute value\n");
5277 /* FIXIT : definitly, we need _BAD_PARAM error code */
5278 return MM_ERROR_INVALID_ARGUMENT;
5281 player->sound.mute = mute;
5283 /* just hold mute value if pipeline is not ready */
5284 if (!player->pipeline || !player->pipeline->audiobin) {
5285 LOGD("pipeline is not ready. holding mute value\n");
5286 return MM_ERROR_NONE;
5289 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5291 /* NOTE : volume will only created when the bt is enabled */
5293 LOGD("mute : %d\n", mute);
5294 g_object_set(vol_element, "mute", mute, NULL);
5296 LOGD("volume elemnet is not created. using volume in audiosink\n");
5300 return MM_ERROR_NONE;
5304 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
5306 mm_player_t* player = (mm_player_t*) hplayer;
5310 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5311 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5313 /* just hold mute value if pipeline is not ready */
5314 if (!player->pipeline || !player->pipeline->audiobin) {
5315 LOGD("pipeline is not ready. returning stored value\n");
5316 *pmute = player->sound.mute;
5317 return MM_ERROR_NONE;
5320 *pmute = player->sound.mute;
5324 return MM_ERROR_NONE;
5328 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5330 mm_player_t* player = (mm_player_t*) hplayer;
5334 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5336 player->video_stream_changed_cb = callback;
5337 player->video_stream_changed_cb_user_param = user_param;
5338 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
5342 return MM_ERROR_NONE;
5346 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5348 mm_player_t* player = (mm_player_t*) hplayer;
5352 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5354 player->audio_stream_changed_cb = callback;
5355 player->audio_stream_changed_cb_user_param = user_param;
5356 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
5360 return MM_ERROR_NONE;
5364 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5366 mm_player_t *player = (mm_player_t*) hplayer;
5370 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5372 player->audio_stream_render_cb = callback;
5373 player->audio_stream_cb_user_param = user_param;
5374 player->audio_stream_sink_sync = sync;
5375 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5379 return MM_ERROR_NONE;
5383 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5385 mm_player_t* player = (mm_player_t*) hplayer;
5389 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5391 if (callback && !player->bufmgr)
5392 player->bufmgr = tbm_bufmgr_init(-1);
5394 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
5395 player->video_stream_cb = callback;
5396 player->video_stream_cb_user_param = user_param;
5398 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5402 return MM_ERROR_NONE;
5406 __mmplayer_start_streaming_ext(mm_player_t *player)
5408 gint ret = MM_ERROR_NONE;
5411 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5413 if (MMPLAYER_IS_HTTP_PD(player)) {
5414 if (!player->pd_downloader) {
5415 ret = __mmplayer_realize_streaming_ext(player);
5417 if (ret != MM_ERROR_NONE) {
5418 LOGE("failed to realize streaming ext\n");
5423 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
5424 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
5426 LOGE("ERROR while starting PD...\n");
5427 return MM_ERROR_PLAYER_NOT_INITIALIZED;
5429 ret = MM_ERROR_NONE;
5438 _mmplayer_start(MMHandleType hplayer)
5440 mm_player_t* player = (mm_player_t*) hplayer;
5441 gint ret = MM_ERROR_NONE;
5445 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5447 /* check current state */
5448 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5450 /* PD - start streaming */
5451 ret = __mmplayer_start_streaming_ext(player);
5452 if (ret != MM_ERROR_NONE) {
5453 LOGE("failed to start streaming ext 0x%X", ret);
5457 /* start pipeline */
5458 ret = __mmplayer_gst_start(player);
5459 if (ret != MM_ERROR_NONE)
5460 LOGE("failed to start player.\n");
5462 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5463 LOGD("force playing start even during buffering");
5464 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5472 /* NOTE: post "not supported codec message" to application
5473 * when one codec is not found during AUTOPLUGGING in MSL.
5474 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5475 * And, if any codec is not found, don't send message here.
5476 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5479 __mmplayer_handle_missed_plugin(mm_player_t* player)
5481 MMMessageParamType msg_param;
5482 memset(&msg_param, 0, sizeof(MMMessageParamType));
5483 gboolean post_msg_direct = FALSE;
5487 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5489 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
5490 player->not_supported_codec, player->can_support_codec);
5492 if (player->not_found_demuxer) {
5493 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5494 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5496 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5497 MMPLAYER_FREEIF(msg_param.data);
5499 return MM_ERROR_NONE;
5502 if (player->not_supported_codec) {
5503 if (player->can_support_codec) {
5504 // There is one codec to play
5505 post_msg_direct = TRUE;
5507 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5508 post_msg_direct = TRUE;
5511 if (post_msg_direct) {
5512 MMMessageParamType msg_param;
5513 memset(&msg_param, 0, sizeof(MMMessageParamType));
5515 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5516 LOGW("not found AUDIO codec, posting error code to application.\n");
5518 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5519 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5520 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5521 LOGW("not found VIDEO codec, posting error code to application.\n");
5523 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5524 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5527 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5529 MMPLAYER_FREEIF(msg_param.data);
5531 return MM_ERROR_NONE;
5533 // no any supported codec case
5534 LOGW("not found any codec, posting error code to application.\n");
5536 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5537 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5538 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5540 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5541 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5544 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5546 MMPLAYER_FREEIF(msg_param.data);
5552 return MM_ERROR_NONE;
5555 static void __mmplayer_check_pipeline(mm_player_t* player)
5557 GstState element_state = GST_STATE_VOID_PENDING;
5558 GstState element_pending_state = GST_STATE_VOID_PENDING;
5560 int ret = MM_ERROR_NONE;
5562 if (player->gapless.reconfigure) {
5563 LOGW("pipeline is under construction.\n");
5565 MMPLAYER_PLAYBACK_LOCK(player);
5566 MMPLAYER_PLAYBACK_UNLOCK(player);
5568 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5570 /* wait for state transition */
5571 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5573 if (ret == GST_STATE_CHANGE_FAILURE)
5574 LOGE("failed to change pipeline state within %d sec\n", timeout);
5578 /* NOTE : it should be able to call 'stop' anytime*/
5580 _mmplayer_stop(MMHandleType hplayer)
5582 mm_player_t* player = (mm_player_t*)hplayer;
5583 int ret = MM_ERROR_NONE;
5587 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5589 /* check current state */
5590 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5592 /* check pipline building state */
5593 __mmplayer_check_pipeline(player);
5594 __mmplayer_reset_gapless_state(player);
5596 /* NOTE : application should not wait for EOS after calling STOP */
5597 __mmplayer_cancel_eos_timer(player);
5599 __mmplayer_unrealize_streaming_ext(player);
5602 player->seek_state = MMPLAYER_SEEK_NONE;
5605 ret = __mmplayer_gst_stop(player);
5607 if (ret != MM_ERROR_NONE)
5608 LOGE("failed to stop player.\n");
5616 _mmplayer_pause(MMHandleType hplayer)
5618 mm_player_t* player = (mm_player_t*)hplayer;
5619 gint64 pos_nsec = 0;
5620 gboolean async = FALSE;
5621 gint ret = MM_ERROR_NONE;
5625 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5627 /* check current state */
5628 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5630 /* check pipline building state */
5631 __mmplayer_check_pipeline(player);
5633 switch (MMPLAYER_CURRENT_STATE(player)) {
5634 case MM_PLAYER_STATE_READY:
5636 /* check prepare async or not.
5637 * In the case of streaming playback, it's recommned to avoid blocking wait.
5639 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5640 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5642 /* Changing back sync of rtspsrc to async */
5643 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5644 LOGD("async prepare working mode for rtsp");
5650 case MM_PLAYER_STATE_PLAYING:
5652 /* NOTE : store current point to overcome some bad operation
5653 *(returning zero when getting current position in paused state) of some
5656 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5657 LOGW("getting current position failed in paused\n");
5659 player->last_position = pos_nsec;
5661 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5662 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5663 This causes problem is position calculation during normal pause resume scenarios also.
5664 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5665 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5666 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5667 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5673 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5674 LOGD("doing async pause in case of ms buff src");
5678 /* pause pipeline */
5679 ret = __mmplayer_gst_pause(player, async);
5681 if (ret != MM_ERROR_NONE)
5682 LOGE("failed to pause player. ret : 0x%x\n", ret);
5684 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5685 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5686 LOGE("failed to update display_rotation");
5694 /* in case of streaming, pause could take long time.*/
5696 _mmplayer_abort_pause(MMHandleType hplayer)
5698 mm_player_t* player = (mm_player_t*)hplayer;
5699 int ret = MM_ERROR_NONE;
5703 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5705 player->pipeline->mainbin,
5706 MM_ERROR_PLAYER_NOT_INITIALIZED);
5708 LOGD("set the pipeline state to READY");
5710 /* set state to READY */
5711 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5712 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5713 if (ret != MM_ERROR_NONE) {
5714 LOGE("fail to change state to READY");
5715 return MM_ERROR_PLAYER_INTERNAL;
5718 LOGD("succeeded in changing state to READY");
5724 _mmplayer_resume(MMHandleType hplayer)
5726 mm_player_t* player = (mm_player_t*)hplayer;
5727 int ret = MM_ERROR_NONE;
5728 gboolean async = FALSE;
5732 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5734 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5735 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5736 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5740 /* Changing back sync mode rtspsrc to async */
5741 LOGD("async resume for rtsp case");
5745 /* check current state */
5746 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5748 ret = __mmplayer_gst_resume(player, async);
5749 if (ret != MM_ERROR_NONE)
5750 LOGE("failed to resume player.\n");
5752 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5753 LOGD("force resume even during buffering");
5754 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5763 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5765 mm_player_t* player = (mm_player_t*)hplayer;
5766 gint64 pos_nsec = 0;
5767 int ret = MM_ERROR_NONE;
5769 signed long long start = 0, stop = 0;
5770 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5773 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5774 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5776 /* The sound of video is not supported under 0.0 and over 2.0. */
5777 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5778 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5781 _mmplayer_set_mute(hplayer, mute);
5783 if (player->playback_rate == rate)
5784 return MM_ERROR_NONE;
5786 /* If the position is reached at start potion during fast backward, EOS is posted.
5787 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5789 player->playback_rate = rate;
5791 current_state = MMPLAYER_CURRENT_STATE(player);
5793 if (current_state != MM_PLAYER_STATE_PAUSED)
5794 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5796 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5798 if ((current_state == MM_PLAYER_STATE_PAUSED)
5799 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5800 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5801 pos_nsec = player->last_position;
5806 stop = GST_CLOCK_TIME_NONE;
5808 start = GST_CLOCK_TIME_NONE;
5812 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5813 player->playback_rate,
5815 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5816 GST_SEEK_TYPE_SET, start,
5817 GST_SEEK_TYPE_SET, stop)) {
5818 LOGE("failed to set speed playback\n");
5819 return MM_ERROR_PLAYER_SEEK;
5822 LOGD("succeeded to set speed playback as %0.1f\n", rate);
5826 return MM_ERROR_NONE;;
5830 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5832 mm_player_t* player = (mm_player_t*)hplayer;
5833 int ret = MM_ERROR_NONE;
5837 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5839 /* check pipline building state */
5840 __mmplayer_check_pipeline(player);
5842 ret = __mmplayer_gst_set_position(player, position, FALSE);
5850 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5852 mm_player_t* player = (mm_player_t*)hplayer;
5853 int ret = MM_ERROR_NONE;
5855 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5857 ret = __mmplayer_gst_get_position(player, position);
5863 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5865 mm_player_t* player = (mm_player_t*)hplayer;
5866 int ret = MM_ERROR_NONE;
5868 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5869 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5871 *duration = player->duration;
5876 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
5878 mm_player_t* player = (mm_player_t*)hplayer;
5879 int ret = MM_ERROR_NONE;
5881 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5883 ret = __mmplayer_gst_get_buffer_position(player, format, start_pos, stop_pos);
5889 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5891 mm_player_t* player = (mm_player_t*)hplayer;
5892 int ret = MM_ERROR_NONE;
5896 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5898 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5906 __mmplayer_is_midi_type(gchar* str_caps)
5908 if ((g_strrstr(str_caps, "audio/midi")) ||
5909 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5910 (g_strrstr(str_caps, "application/x-smaf")) ||
5911 (g_strrstr(str_caps, "audio/x-imelody")) ||
5912 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5913 (g_strrstr(str_caps, "audio/xmf")) ||
5914 (g_strrstr(str_caps, "audio/mxmf"))) {
5923 __mmplayer_is_only_mp3_type(gchar *str_caps)
5925 if (g_strrstr(str_caps, "application/x-id3") ||
5926 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5932 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
5934 GstStructure* caps_structure = NULL;
5935 gint samplerate = 0;
5939 MMPLAYER_RETURN_IF_FAIL(player && caps);
5941 caps_structure = gst_caps_get_structure(caps, 0);
5943 /* set stream information */
5944 gst_structure_get_int(caps_structure, "rate", &samplerate);
5945 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5947 gst_structure_get_int(caps_structure, "channels", &channels);
5948 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5950 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
5954 __mmplayer_update_content_type_info(mm_player_t* player)
5957 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5959 if (__mmplayer_is_midi_type(player->type)) {
5960 player->bypass_audio_effect = TRUE;
5961 } else if (g_strrstr(player->type, "application/x-hls")) {
5962 /* If it can't know exact type when it parses uri because of redirection case,
5963 * it will be fixed by typefinder or when doing autoplugging.
5965 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5966 if (player->streamer) {
5967 player->streamer->is_adaptive_streaming = TRUE;
5968 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5969 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
5971 } else if (g_strrstr(player->type, "application/dash+xml")) {
5972 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5973 if (player->streamer) {
5974 player->streamer->is_adaptive_streaming = TRUE;
5975 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5979 LOGD("uri type : %d", player->profile.uri_type);
5984 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5985 GstCaps *caps, gpointer data)
5987 mm_player_t* player = (mm_player_t*)data;
5992 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5994 /* store type string */
5995 MMPLAYER_FREEIF(player->type);
5996 player->type = gst_caps_to_string(caps);
5998 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
5999 player, player->type, probability, gst_caps_get_size(caps));
6002 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
6003 (g_strrstr(player->type, "audio/x-raw-int"))) {
6004 LOGE("not support media format\n");
6006 if (player->msg_posted == FALSE) {
6007 MMMessageParamType msg_param;
6008 memset(&msg_param, 0, sizeof(MMMessageParamType));
6010 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6011 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6013 /* don't post more if one was sent already */
6014 player->msg_posted = TRUE;
6019 __mmplayer_update_content_type_info(player);
6021 pad = gst_element_get_static_pad(tf, "src");
6023 LOGE("fail to get typefind src pad.\n");
6027 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
6028 gboolean async = FALSE;
6029 LOGE("failed to autoplug %s\n", player->type);
6031 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6033 if (async && player->msg_posted == FALSE)
6034 __mmplayer_handle_missed_plugin(player);
6040 gst_object_unref(GST_OBJECT(pad));
6048 __mmplayer_gst_make_decodebin(mm_player_t* player)
6050 GstElement *decodebin = NULL;
6054 /* create decodebin */
6055 decodebin = gst_element_factory_make("decodebin", NULL);
6058 LOGE("fail to create decodebin\n");
6062 /* raw pad handling signal */
6063 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6064 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
6066 /* no-more-pad pad handling signal */
6067 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6068 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
6070 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6071 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
6073 /* This signal is emitted when a pad for which there is no further possible
6074 decoding is added to the decodebin.*/
6075 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6076 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
6078 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6079 before looking for any elements that can handle that stream.*/
6080 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6081 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6083 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6084 before looking for any elements that can handle that stream.*/
6085 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6086 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
6088 /* This signal is emitted once decodebin has finished decoding all the data.*/
6089 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6090 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
6092 /* This signal is emitted when a element is added to the bin.*/
6093 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6094 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
6101 __mmplayer_gst_make_queue2(mm_player_t *player)
6103 GstElement* queue2 = NULL;
6104 gint64 dur_bytes = 0L;
6105 guint max_buffer_size_bytes = 0;
6106 MMPlayerGstElement *mainbin = NULL;
6107 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6110 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6112 mainbin = player->pipeline->mainbin;
6114 queue2 = gst_element_factory_make("queue2", "queue2");
6116 LOGE("failed to create buffering queue element");
6120 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6121 LOGE("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6123 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6125 if (dur_bytes > 0) {
6126 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
6127 type = MUXED_BUFFER_TYPE_FILE;
6129 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6130 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6136 /* NOTE : in case of ts streaming, player cannot get the correct duration info *
6137 * skip the pull mode(file or ring buffering) setting. */
6138 if (!g_strrstr(player->type, "video/mpegts")) {
6139 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
6140 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
6142 __mm_player_streaming_set_queue2(player->streamer,
6145 max_buffer_size_bytes,
6146 player->ini.http_buffering_time,
6147 1.0, /* no meaning */
6148 player->ini.http_buffering_limit, /* no meaning */
6150 player->http_file_buffering_path,
6151 (guint64)dur_bytes);
6158 __mmplayer_gst_create_decoder(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
6160 MMPlayerGstElement* mainbin = NULL;
6161 GstElement* decodebin = NULL;
6162 GstElement* queue2 = NULL;
6163 GstPad* sinkpad = NULL;
6164 GstPad* qsrcpad = NULL;
6165 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6168 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6170 mainbin = player->pipeline->mainbin;
6172 if ((!MMPLAYER_IS_HTTP_PD(player)) && (MMPLAYER_IS_HTTP_STREAMING(player))) {
6174 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6175 LOGW("need to check: muxed buffer is not null");
6178 queue2 = __mmplayer_gst_make_queue2(player);
6180 LOGE("failed to make queue2");
6184 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6185 LOGE("failed to add buffering queue");
6189 sinkpad = gst_element_get_static_pad(queue2, "sink");
6190 qsrcpad = gst_element_get_static_pad(queue2, "src");
6192 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6193 LOGE("failed to link [%s:%s]-[%s:%s]",
6194 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6198 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6199 LOGE("failed to sync queue2 state with parent");
6203 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6204 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6208 gst_object_unref(GST_OBJECT(sinkpad));
6212 /* create decodebin */
6213 decodebin = __mmplayer_gst_make_decodebin(player);
6215 LOGE("failed to make decodebin");
6219 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6220 LOGE("failed to add decodebin\n");
6224 /* to force caps on the decodebin element and avoid reparsing stuff by
6225 * typefind. It also avoids a deadlock in the way typefind activates pads in
6226 * the state change */
6227 g_object_set(decodebin, "sink-caps", caps, NULL);
6229 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6231 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6232 LOGE("failed to link [%s:%s]-[%s:%s]",
6233 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6237 gst_object_unref(GST_OBJECT(sinkpad));
6240 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6241 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6243 /* set decodebin property about buffer in streaming playback. *
6244 * in case of HLS/DASH, it does not need to have big buffer *
6245 * because it is kind of adaptive streaming. */
6246 if (!MMPLAYER_IS_HTTP_PD(player) &&
6247 (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player))) {
6248 gdouble high_percent = 0.0;
6250 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
6251 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
6253 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
6254 GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
6256 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6257 "high-percent", (gint)high_percent,
6258 "low-percent", (gint)DEFAULT_BUFFER_LOW_PERCENT,
6259 "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
6260 "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
6261 "max-size-buffers", 0, NULL); // disable or automatic
6264 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
6265 LOGE("failed to sync decodebin state with parent\n");
6276 gst_object_unref(GST_OBJECT(sinkpad));
6279 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6280 * You need to explicitly set elements to the NULL state before
6281 * dropping the final reference, to allow them to clean up.
6283 gst_element_set_state(queue2, GST_STATE_NULL);
6285 /* And, it still has a parent "player".
6286 * You need to let the parent manage the object instead of unreffing the object directly.
6288 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6289 gst_object_unref(queue2);
6294 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6295 * You need to explicitly set elements to the NULL state before
6296 * dropping the final reference, to allow them to clean up.
6298 gst_element_set_state(decodebin, GST_STATE_NULL);
6300 /* And, it still has a parent "player".
6301 * You need to let the parent manage the object instead of unreffing the object directly.
6304 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6305 gst_object_unref(decodebin);
6313 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
6317 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6318 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6320 LOGD("class : %s, mime : %s \n", factory_class, mime);
6322 /* add missing plugin */
6323 /* NOTE : msl should check missing plugin for image mime type.
6324 * Some motion jpeg clips can have playable audio track.
6325 * So, msl have to play audio after displaying popup written video format not supported.
6327 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6328 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6329 LOGD("not found demuxer\n");
6330 player->not_found_demuxer = TRUE;
6331 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6337 if (!g_strrstr(factory_class, "Demuxer")) {
6338 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6339 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
6340 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6342 /* check that clip have multi tracks or not */
6343 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6344 LOGD("video plugin is already linked\n");
6346 LOGW("add VIDEO to missing plugin\n");
6347 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6348 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6350 } else if (g_str_has_prefix(mime, "audio")) {
6351 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6352 LOGD("audio plugin is already linked\n");
6354 LOGW("add AUDIO to missing plugin\n");
6355 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6356 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6364 return MM_ERROR_NONE;
6369 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6371 mm_player_t* player = (mm_player_t*)data;
6375 MMPLAYER_RETURN_IF_FAIL(player);
6377 /* remove fakesink. */
6378 if (!__mmplayer_gst_remove_fakesink(player,
6379 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6380 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6381 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6382 * source element are not same. To overcome this situation, this function will called
6383 * several places and several times. Therefore, this is not an error case.
6388 LOGD("[handle: %p] pipeline has completely constructed", player);
6390 if ((player->ini.async_start) &&
6391 (player->msg_posted == FALSE) &&
6392 (player->cmd >= MMPLAYER_COMMAND_START))
6393 __mmplayer_handle_missed_plugin(player);
6395 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6399 __mmplayer_check_profile(void)
6402 static int profile_tv = -1;
6404 if (__builtin_expect(profile_tv != -1, 1))
6407 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6408 switch (*profileName) {
6423 __mmplayer_get_next_uri(mm_player_t *player)
6425 MMPlayerParseProfile profile;
6427 guint num_of_list = 0;
6430 num_of_list = g_list_length(player->uri_info.uri_list);
6431 uri_idx = player->uri_info.uri_idx;
6433 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6434 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6435 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6437 LOGW("next uri does not exist");
6441 if (__mmplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
6442 LOGE("failed to parse profile");
6446 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6447 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6448 LOGW("uri type is not supported(%d)", profile.uri_type);
6452 LOGD("success to find next uri %d", uri_idx);
6456 if (uri_idx == num_of_list) {
6457 LOGE("failed to find next uri");
6461 player->uri_info.uri_idx = uri_idx;
6462 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6464 if (mmf_attrs_commit(player->attrs)) {
6465 LOGE("failed to commit");
6469 SECURE_LOGD("next playback uri: %s", uri);
6474 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6476 #define REPEAT_COUNT_INFINITELY -1
6477 #define REPEAT_COUNT_MIN 2
6479 MMHandleType attrs = 0;
6480 gint mode = MM_PLAYER_PD_MODE_NONE;
6484 guint num_of_list = 0;
6485 int profile_tv = -1;
6489 LOGD("checking for gapless play option");
6491 if (player->pipeline->textbin) {
6492 LOGE("subtitle path is enabled. gapless play is not supported.\n");
6496 attrs = MMPLAYER_GET_ATTRS(player);
6498 LOGE("fail to get attributes.\n");
6502 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6504 /* gapless playback is not supported in case of video at TV profile. */
6505 profile_tv = __mmplayer_check_profile();
6506 if (profile_tv && video) {
6507 LOGW("not support video gapless playback");
6511 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
6518 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6519 LOGE("failed to get play count");
6521 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6522 LOGE("failed to get gapless mode");
6524 /* check repeat count in case of audio */
6526 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6527 LOGW("gapless is disabled");
6531 num_of_list = g_list_length(player->uri_info.uri_list);
6533 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6535 if (num_of_list == 0) {
6536 /* audio looping path */
6537 if (count >= REPEAT_COUNT_MIN) {
6538 /* decrease play count */
6539 /* we succeeded to rewind. update play count and then wait for next EOS */
6542 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6544 /* commit attribute */
6545 if (mmf_attrs_commit(attrs))
6546 LOGE("failed to commit attribute");
6547 } else if (count != REPEAT_COUNT_INFINITELY) {
6548 LOGD("there is no next uri and no repeat");
6552 LOGD("looping cnt %d", count);
6554 /* gapless playback path */
6555 if (!__mmplayer_get_next_uri(player)) {
6556 LOGE("failed to get next uri");
6564 LOGE("unable to play gapless path. EOS will be posted soon");
6569 __mmplayer_initialize_gapless_play(mm_player_t *player)
6575 player->smooth_streaming = FALSE;
6576 player->videodec_linked = 0;
6577 player->audiodec_linked = 0;
6578 player->videosink_linked = 0;
6579 player->audiosink_linked = 0;
6580 player->textsink_linked = 0;
6581 player->is_external_subtitle_present = FALSE;
6582 player->is_external_subtitle_added_now = FALSE;
6583 player->not_supported_codec = MISSING_PLUGIN_NONE;
6584 player->can_support_codec = FOUND_PLUGIN_NONE;
6585 player->pending_seek.is_pending = FALSE;
6586 player->pending_seek.pos = 0;
6587 player->msg_posted = FALSE;
6588 player->has_many_types = FALSE;
6589 player->no_more_pad = FALSE;
6590 player->not_found_demuxer = 0;
6591 player->seek_state = MMPLAYER_SEEK_NONE;
6592 player->is_subtitle_force_drop = FALSE;
6593 player->play_subtitle = FALSE;
6594 player->adjust_subtitle_pos = 0;
6596 player->total_bitrate = 0;
6597 player->total_maximum_bitrate = 0;
6599 __mmplayer_track_initialize(player);
6600 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6602 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6603 player->bitrate[i] = 0;
6604 player->maximum_bitrate[i] = 0;
6607 if (player->v_stream_caps) {
6608 gst_caps_unref(player->v_stream_caps);
6609 player->v_stream_caps = NULL;
6612 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6614 /* clean found parsers */
6615 if (player->parsers) {
6616 GList *parsers = player->parsers;
6617 for (; parsers; parsers = g_list_next(parsers)) {
6618 gchar *name = parsers->data;
6619 MMPLAYER_FREEIF(name);
6621 g_list_free(player->parsers);
6622 player->parsers = NULL;
6625 /* clean found audio decoders */
6626 if (player->audio_decoders) {
6627 GList *a_dec = player->audio_decoders;
6628 for (; a_dec; a_dec = g_list_next(a_dec)) {
6629 gchar *name = a_dec->data;
6630 MMPLAYER_FREEIF(name);
6632 g_list_free(player->audio_decoders);
6633 player->audio_decoders = NULL;
6640 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6642 MMPlayerGstElement *mainbin = NULL;
6643 MMMessageParamType msg_param = {0,};
6644 GstElement *element = NULL;
6645 MMHandleType attrs = 0;
6647 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6651 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6652 LOGE("player is not initialized");
6656 mainbin = player->pipeline->mainbin;
6657 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6659 attrs = MMPLAYER_GET_ATTRS(player);
6661 LOGE("fail to get attributes");
6665 /* Initialize Player values */
6666 __mmplayer_initialize_gapless_play(player);
6668 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6670 if (__mmplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6671 LOGE("failed to parse profile");
6672 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6676 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6677 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6678 LOGE("dash or hls is not supportable");
6679 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6683 element = __mmplayer_gst_create_source(player);
6685 LOGE("no source element was created");
6689 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6690 LOGE("failed to add source element to pipeline");
6691 gst_object_unref(GST_OBJECT(element));
6696 /* take source element */
6697 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6698 mainbin[MMPLAYER_M_SRC].gst = element;
6702 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6703 if (player->streamer == NULL) {
6704 player->streamer = __mm_player_streaming_create();
6705 __mm_player_streaming_initialize(player->streamer);
6708 elem_idx = MMPLAYER_M_TYPEFIND;
6709 element = gst_element_factory_make("typefind", "typefinder");
6710 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6711 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6713 elem_idx = MMPLAYER_M_AUTOPLUG;
6714 element = __mmplayer_gst_make_decodebin(player);
6717 /* check autoplug element is OK */
6719 LOGE("can not create element(%d)", elem_idx);
6723 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6724 LOGE("failed to add sinkbin to pipeline");
6725 gst_object_unref(GST_OBJECT(element));
6730 mainbin[elem_idx].id = elem_idx;
6731 mainbin[elem_idx].gst = element;
6733 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6734 LOGE("Failed to link src - autoplug(or typefind)");
6738 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6739 LOGE("Failed to change state of src element");
6743 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6744 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6745 LOGE("Failed to change state of decodebin");
6749 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6750 LOGE("Failed to change state of src element");
6755 player->gapless.stream_changed = TRUE;
6756 player->gapless.running = TRUE;
6762 MMPLAYER_PLAYBACK_UNLOCK(player);
6764 if (!player->msg_posted) {
6765 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6766 player->msg_posted = TRUE;
6773 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6775 mm_player_selector_t *selector = &player->selector[type];
6776 MMPlayerGstElement *sinkbin = NULL;
6777 enum MainElementID selectorId = MMPLAYER_M_NUM;
6778 enum MainElementID sinkId = MMPLAYER_M_NUM;
6779 GstPad *srcpad = NULL;
6780 GstPad *sinkpad = NULL;
6781 gboolean send_notice = FALSE;
6784 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6786 LOGD("type %d", type);
6789 case MM_PLAYER_TRACK_TYPE_AUDIO:
6790 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6791 sinkId = MMPLAYER_A_BIN;
6792 sinkbin = player->pipeline->audiobin;
6794 case MM_PLAYER_TRACK_TYPE_VIDEO:
6795 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6796 sinkId = MMPLAYER_V_BIN;
6797 sinkbin = player->pipeline->videobin;
6800 case MM_PLAYER_TRACK_TYPE_TEXT:
6801 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6802 sinkId = MMPLAYER_T_BIN;
6803 sinkbin = player->pipeline->textbin;
6806 LOGE("requested type is not supportable");
6811 if (player->pipeline->mainbin[selectorId].gst) {
6814 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6816 if (selector->event_probe_id != 0)
6817 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6818 selector->event_probe_id = 0;
6820 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6821 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6823 if (srcpad && sinkpad) {
6824 /* after getting drained signal there is no data flows, so no need to do pad_block */
6825 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6826 gst_pad_unlink(srcpad, sinkpad);
6828 /* send custom event to sink pad to handle it at video sink */
6830 LOGD("send custom event to sinkpad");
6831 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6832 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6833 gst_pad_send_event(sinkpad, event);
6837 gst_object_unref(sinkpad);
6840 gst_object_unref(srcpad);
6843 LOGD("selector release");
6845 /* release and unref requests pad from the selector */
6846 for (n = 0; n < selector->channels->len; n++) {
6847 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6848 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6850 g_ptr_array_set_size(selector->channels, 0);
6852 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6853 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6855 player->pipeline->mainbin[selectorId].gst = NULL;
6863 __mmplayer_deactivate_old_path(mm_player_t *player)
6866 MMPLAYER_RETURN_IF_FAIL(player);
6868 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6869 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6870 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6871 LOGE("deactivate selector error");
6875 __mmplayer_track_destroy(player);
6876 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6878 if (player->streamer) {
6879 __mm_player_streaming_deinitialize(player->streamer);
6880 __mm_player_streaming_destroy(player->streamer);
6881 player->streamer = NULL;
6884 MMPLAYER_PLAYBACK_LOCK(player);
6885 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6892 if (!player->msg_posted) {
6893 MMMessageParamType msg = {0,};
6896 msg.code = MM_ERROR_PLAYER_INTERNAL;
6897 LOGE("gapless_uri_play> deactivate error");
6899 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6900 player->msg_posted = TRUE;
6905 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
6907 int result = MM_ERROR_NONE;
6908 mm_player_t* player = (mm_player_t*) hplayer;
6911 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6914 player->http_file_buffering_path = (gchar*)file_path;
6915 LOGD("temp file path: %s\n", player->http_file_buffering_path);
6921 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
6923 int result = MM_ERROR_NONE;
6924 mm_player_t* player = (mm_player_t*) hplayer;
6927 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6929 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6930 if (mmf_attrs_commit(player->attrs)) {
6931 LOGE("failed to commit the original uri.\n");
6932 result = MM_ERROR_PLAYER_INTERNAL;
6934 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6935 LOGE("failed to add the original uri in the uri list.\n");
6942 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
6944 mm_player_t* player = (mm_player_t*) hplayer;
6945 guint num_of_list = 0;
6949 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6950 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6952 if (player->pipeline && player->pipeline->textbin) {
6953 LOGE("subtitle path is enabled.\n");
6954 return MM_ERROR_PLAYER_INVALID_STATE;
6957 num_of_list = g_list_length(player->uri_info.uri_list);
6959 if (is_first_path == TRUE) {
6960 if (num_of_list == 0) {
6961 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6962 LOGD("add original path : %s", uri);
6964 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6965 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6967 LOGD("change original path : %s", uri);
6970 MMHandleType attrs = 0;
6971 attrs = MMPLAYER_GET_ATTRS(player);
6973 if (num_of_list == 0) {
6974 char *original_uri = NULL;
6977 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6979 if (!original_uri) {
6980 LOGE("there is no original uri.");
6981 return MM_ERROR_PLAYER_INVALID_STATE;
6984 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6985 player->uri_info.uri_idx = 0;
6987 LOGD("add original path at first : %s(%d)", original_uri);
6991 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6992 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6996 return MM_ERROR_NONE;
6999 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
7001 mm_player_t* player = (mm_player_t*) hplayer;
7002 char *next_uri = NULL;
7003 guint num_of_list = 0;
7006 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7008 num_of_list = g_list_length(player->uri_info.uri_list);
7010 if (num_of_list > 0) {
7011 gint uri_idx = player->uri_info.uri_idx;
7013 if (uri_idx < num_of_list-1)
7018 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
7019 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
7021 *uri = g_strdup(next_uri);
7025 return MM_ERROR_NONE;
7029 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
7030 GstCaps *caps, gpointer data)
7032 mm_player_t* player = (mm_player_t*)data;
7033 const gchar* klass = NULL;
7034 const gchar* mime = NULL;
7035 gchar* caps_str = NULL;
7037 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
7038 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
7039 caps_str = gst_caps_to_string(caps);
7041 LOGW("unknown type of caps : %s from %s",
7042 caps_str, GST_ELEMENT_NAME(elem));
7044 MMPLAYER_FREEIF(caps_str);
7046 /* There is no available codec. */
7047 __mmplayer_check_not_supported_codec(player, klass, mime);
7051 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
7052 GstCaps * caps, gpointer data)
7054 mm_player_t* player = (mm_player_t*)data;
7055 const char* mime = NULL;
7056 gboolean ret = TRUE;
7058 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
7059 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
7061 if (g_str_has_prefix(mime, "audio")) {
7062 GstStructure* caps_structure = NULL;
7063 gint samplerate = 0;
7065 gchar *caps_str = NULL;
7067 caps_structure = gst_caps_get_structure(caps, 0);
7068 gst_structure_get_int(caps_structure, "rate", &samplerate);
7069 gst_structure_get_int(caps_structure, "channels", &channels);
7071 if ((channels > 0 && samplerate == 0)) {
7072 LOGD("exclude audio...");
7076 caps_str = gst_caps_to_string(caps);
7077 /* set it directly because not sent by TAG */
7078 if (g_strrstr(caps_str, "mobile-xmf"))
7079 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
7080 MMPLAYER_FREEIF(caps_str);
7081 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
7082 MMMessageParamType msg_param;
7083 memset(&msg_param, 0, sizeof(MMMessageParamType));
7084 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
7085 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
7086 LOGD("video file is not supported on this device");
7088 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
7089 LOGD("already video linked");
7092 LOGD("found new stream");
7099 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
7101 int ret = MM_ERROR_NONE;
7103 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7105 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7106 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7108 LOGD("audio codec type: %d", codec_type);
7109 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7110 /* sw codec will be skipped */
7111 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7112 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7113 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7114 ret = MM_ERROR_PLAYER_INTERNAL;
7118 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7119 /* hw codec will be skipped */
7120 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7121 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7122 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7123 ret = MM_ERROR_PLAYER_INTERNAL;
7128 /* set stream information */
7129 if (!player->audiodec_linked)
7130 __mmplayer_set_audio_attrs(player, caps);
7132 /* update codec info */
7133 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7134 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7135 player->audiodec_linked = 1;
7137 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7139 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7141 LOGD("video codec type: %d", codec_type);
7142 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7143 /* sw codec is skipped */
7144 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7145 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7146 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7147 ret = MM_ERROR_PLAYER_INTERNAL;
7151 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7152 /* hw codec is skipped */
7153 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7154 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7155 ret = MM_ERROR_PLAYER_INTERNAL;
7160 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7161 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7163 /* mark video decoder for acquire */
7164 if (player->video_decoder_resource == NULL) {
7165 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
7166 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
7167 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
7168 &player->video_decoder_resource)
7169 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7170 LOGE("could not mark video_decoder resource for acquire");
7171 ret = MM_ERROR_PLAYER_INTERNAL;
7175 LOGW("video decoder resource is already acquired, skip it.");
7176 ret = MM_ERROR_PLAYER_INTERNAL;
7180 player->interrupted_by_resource = FALSE;
7181 /* acquire resources for video playing */
7182 if (mm_resource_manager_commit(player->resource_manager)
7183 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7184 LOGE("could not acquire resources for video decoding\n");
7185 ret = MM_ERROR_PLAYER_INTERNAL;
7190 /* update codec info */
7191 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7192 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7193 player->videodec_linked = 1;
7201 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
7202 GstCaps* caps, GstElementFactory* factory, gpointer data)
7204 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
7205 We are defining our own and will be removed when it actually exposed */
7207 GST_AUTOPLUG_SELECT_TRY,
7208 GST_AUTOPLUG_SELECT_EXPOSE,
7209 GST_AUTOPLUG_SELECT_SKIP
7210 } GstAutoplugSelectResult;
7212 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7213 mm_player_t* player = (mm_player_t*)data;
7215 gchar* factory_name = NULL;
7216 gchar* caps_str = NULL;
7217 const gchar* klass = NULL;
7220 factory_name = GST_OBJECT_NAME(factory);
7221 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7222 caps_str = gst_caps_to_string(caps);
7224 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7226 /* store type string */
7227 if (player->type == NULL) {
7228 player->type = gst_caps_to_string(caps);
7229 __mmplayer_update_content_type_info(player);
7232 /* filtering exclude keyword */
7233 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7234 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7235 LOGW("skipping [%s] by exculde keyword [%s]",
7236 factory_name, player->ini.exclude_element_keyword[idx]);
7238 result = GST_AUTOPLUG_SELECT_SKIP;
7243 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7244 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7245 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7246 factory_name, player->ini.unsupported_codec_keyword[idx]);
7247 result = GST_AUTOPLUG_SELECT_SKIP;
7252 /* exclude webm format */
7253 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7254 * because webm format is not supportable.
7255 * If webm is disabled in "autoplug-continue", there is no state change
7256 * failure or error because the decodebin will expose the pad directly.
7257 * It make MSL invoke _prepare_async_callback.
7258 * So, we need to disable webm format in "autoplug-select" */
7259 if (caps_str && strstr(caps_str, "webm")) {
7260 LOGW("webm is not supported");
7261 result = GST_AUTOPLUG_SELECT_SKIP;
7265 /* check factory class for filtering */
7266 /* NOTE : msl don't need to use image plugins.
7267 * So, those plugins should be skipped for error handling.
7269 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7270 LOGD("skipping [%s] by not required\n", factory_name);
7271 result = GST_AUTOPLUG_SELECT_SKIP;
7275 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7276 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7277 // TO CHECK : subtitle if needed, add subparse exception.
7278 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
7279 result = GST_AUTOPLUG_SELECT_SKIP;
7283 if (g_strrstr(factory_name, "mpegpsdemux")) {
7284 LOGD("skipping PS container - not support\n");
7285 result = GST_AUTOPLUG_SELECT_SKIP;
7289 if (g_strrstr(factory_name, "mssdemux"))
7290 player->smooth_streaming = TRUE;
7292 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7293 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7296 GstStructure *str = NULL;
7297 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7299 /* don't make video because of not required */
7300 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7301 (player->set_mode.media_packet_video_stream == FALSE)) {
7302 LOGD("no video because it's not required. -> return expose");
7303 result = GST_AUTOPLUG_SELECT_EXPOSE;
7307 /* get w/h for omx state-tune */
7308 /* FIXME: deprecated? */
7309 str = gst_caps_get_structure(caps, 0);
7310 gst_structure_get_int(str, "width", &width);
7313 if (player->v_stream_caps) {
7314 gst_caps_unref(player->v_stream_caps);
7315 player->v_stream_caps = NULL;
7318 player->v_stream_caps = gst_caps_copy(caps);
7319 LOGD("take caps for video state tune");
7320 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7324 if (g_strrstr(klass, "Codec/Decoder")) {
7325 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
7326 LOGD("skipping %s codec", factory_name);
7327 result = GST_AUTOPLUG_SELECT_SKIP;
7333 MMPLAYER_FREEIF(caps_str);
7339 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
7342 //mm_player_t* player = (mm_player_t*)data;
7343 GstCaps* caps = NULL;
7345 LOGD("[Decodebin2] pad-removed signal\n");
7347 caps = gst_pad_query_caps(new_pad, NULL);
7349 gchar* caps_str = NULL;
7350 caps_str = gst_caps_to_string(caps);
7352 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7354 MMPLAYER_FREEIF(caps_str);
7355 gst_caps_unref(caps);
7360 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7362 mm_player_t* player = (mm_player_t*)data;
7363 GstIterator *iter = NULL;
7364 GValue item = { 0, };
7366 gboolean done = FALSE;
7367 gboolean is_all_drained = TRUE;
7370 MMPLAYER_RETURN_IF_FAIL(player);
7372 LOGD("__mmplayer_gst_decode_drained");
7374 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7375 LOGW("Fail to get cmd lock");
7379 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7380 !__mmplayer_verify_gapless_play_path(player)) {
7381 LOGD("decoding is finished.");
7382 __mmplayer_reset_gapless_state(player);
7383 MMPLAYER_CMD_UNLOCK(player);
7387 player->gapless.reconfigure = TRUE;
7389 /* check decodebin src pads whether they received EOS or not */
7390 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7393 switch (gst_iterator_next(iter, &item)) {
7394 case GST_ITERATOR_OK:
7395 pad = g_value_get_object(&item);
7396 if (pad && !GST_PAD_IS_EOS(pad)) {
7397 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7398 is_all_drained = FALSE;
7401 g_value_reset(&item);
7403 case GST_ITERATOR_RESYNC:
7404 gst_iterator_resync(iter);
7406 case GST_ITERATOR_ERROR:
7407 case GST_ITERATOR_DONE:
7412 g_value_unset(&item);
7413 gst_iterator_free(iter);
7415 if (!is_all_drained) {
7416 LOGD("Wait util the all pads get EOS.");
7417 MMPLAYER_CMD_UNLOCK(player);
7422 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7423 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7425 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7426 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7427 __mmplayer_deactivate_old_path(player);
7428 MMPLAYER_CMD_UNLOCK(player);
7434 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7436 mm_player_t* player = (mm_player_t*)data;
7437 const gchar* klass = NULL;
7438 gchar* factory_name = NULL;
7440 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7441 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7443 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
7445 if (__mmplayer_add_dump_buffer_probe(player, element))
7446 LOGD("add buffer probe");
7449 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7450 gchar* selected = NULL;
7451 selected = g_strdup(GST_ELEMENT_NAME(element));
7452 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7456 if (g_strrstr(klass, "Parser")) {
7457 gchar* selected = NULL;
7459 selected = g_strdup(factory_name);
7460 player->parsers = g_list_append(player->parsers, selected);
7463 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7464 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7465 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7467 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7468 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7470 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7471 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7472 "max-video-width", player->adaptive_info.limit.width,
7473 "max-video-height", player->adaptive_info.limit.height, NULL);
7475 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
7476 /* FIXIT : first value will be overwritten if there's more
7477 * than 1 demuxer/parser
7480 //LOGD("plugged element is demuxer. take it\n");
7481 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7482 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7484 /*Added for multi audio support */ // Q. del?
7485 if (g_strrstr(klass, "Demux")) {
7486 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
7487 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
7491 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7492 int surface_type = 0;
7494 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7497 // to support trust-zone only
7498 if (g_strrstr(factory_name, "asfdemux")) {
7499 LOGD("set file-location %s\n", player->profile.uri);
7500 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7502 if (player->video_hub_download_mode == TRUE)
7503 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
7504 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7505 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
7506 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7507 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7508 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7509 (__mmplayer_is_only_mp3_type(player->type))) {
7510 LOGD("[mpegaudioparse] set streaming pull mode.");
7511 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7513 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7514 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7517 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7518 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7519 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7521 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7522 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7524 if (!MMPLAYER_IS_HTTP_PD(player) &&
7525 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7526 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7527 (MMPLAYER_IS_DASH_STREAMING(player)))) {
7528 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7529 __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time, 1.0, player->ini.http_buffering_limit);
7530 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7539 __mmplayer_release_misc(mm_player_t* player)
7542 bool cur_mode = player->set_mode.rich_audio;
7545 MMPLAYER_RETURN_IF_FAIL(player);
7547 player->video_stream_cb = NULL;
7548 player->video_stream_cb_user_param = NULL;
7549 player->video_stream_prerolled = FALSE;
7551 player->audio_stream_render_cb = NULL;
7552 player->audio_stream_cb_user_param = NULL;
7553 player->audio_stream_sink_sync = false;
7555 player->video_stream_changed_cb = NULL;
7556 player->video_stream_changed_cb_user_param = NULL;
7558 player->audio_stream_changed_cb = NULL;
7559 player->audio_stream_changed_cb_user_param = NULL;
7561 player->sent_bos = FALSE;
7562 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7564 player->seek_state = MMPLAYER_SEEK_NONE;
7566 player->total_bitrate = 0;
7567 player->total_maximum_bitrate = 0;
7569 player->not_found_demuxer = 0;
7571 player->last_position = 0;
7572 player->duration = 0;
7573 player->http_content_size = 0;
7574 player->not_supported_codec = MISSING_PLUGIN_NONE;
7575 player->can_support_codec = FOUND_PLUGIN_NONE;
7576 player->pending_seek.is_pending = FALSE;
7577 player->pending_seek.pos = 0;
7578 player->msg_posted = FALSE;
7579 player->has_many_types = FALSE;
7580 player->is_subtitle_force_drop = FALSE;
7581 player->play_subtitle = FALSE;
7582 player->adjust_subtitle_pos = 0;
7583 player->last_multiwin_status = FALSE;
7584 player->has_closed_caption = FALSE;
7585 player->set_mode.media_packet_video_stream = FALSE;
7586 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7587 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7589 player->set_mode.rich_audio = cur_mode;
7591 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7592 player->bitrate[i] = 0;
7593 player->maximum_bitrate[i] = 0;
7596 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7598 /* remove media stream cb(appsrc cb) */
7599 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7600 player->media_stream_buffer_status_cb[i] = NULL;
7601 player->media_stream_seek_data_cb[i] = NULL;
7602 player->buffer_cb_user_param[i] = NULL;
7603 player->seek_cb_user_param[i] = NULL;
7605 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7607 /* free memory related to audio effect */
7608 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7610 if (player->adaptive_info.var_list) {
7611 g_list_free_full(player->adaptive_info.var_list, g_free);
7612 player->adaptive_info.var_list = NULL;
7615 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7616 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7617 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7619 /* Reset video360 settings to their defaults in case if the pipeline is to be
7622 player->video360_metadata.is_spherical = -1;
7623 player->is_openal_plugin_used = FALSE;
7625 player->is_content_spherical = FALSE;
7626 player->is_video360_enabled = TRUE;
7627 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7628 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7629 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7630 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7631 player->video360_zoom = 1.0f;
7632 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7633 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7635 player->sound.rg_enable = false;
7637 __mmplayer_initialize_video_roi(player);
7642 __mmplayer_release_misc_post(mm_player_t* player)
7644 char *original_uri = NULL;
7647 /* player->pipeline is already released before. */
7649 MMPLAYER_RETURN_IF_FAIL(player);
7651 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7653 /* clean found parsers */
7654 if (player->parsers) {
7655 GList *parsers = player->parsers;
7656 for (; parsers; parsers = g_list_next(parsers)) {
7657 gchar *name = parsers->data;
7658 MMPLAYER_FREEIF(name);
7660 g_list_free(player->parsers);
7661 player->parsers = NULL;
7664 /* clean found audio decoders */
7665 if (player->audio_decoders) {
7666 GList *a_dec = player->audio_decoders;
7667 for (; a_dec; a_dec = g_list_next(a_dec)) {
7668 gchar *name = a_dec->data;
7669 MMPLAYER_FREEIF(name);
7671 g_list_free(player->audio_decoders);
7672 player->audio_decoders = NULL;
7675 /* clean the uri list except original uri */
7676 if (player->uri_info.uri_list) {
7677 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7679 if (player->attrs) {
7680 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7681 LOGD("restore original uri = %s\n", original_uri);
7683 if (mmf_attrs_commit(player->attrs))
7684 LOGE("failed to commit the original uri.\n");
7687 GList *uri_list = player->uri_info.uri_list;
7688 for (; uri_list; uri_list = g_list_next(uri_list)) {
7689 gchar *uri = uri_list->data;
7690 MMPLAYER_FREEIF(uri);
7692 g_list_free(player->uri_info.uri_list);
7693 player->uri_info.uri_list = NULL;
7696 /* clear the audio stream buffer list */
7697 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7699 /* clear the video stream bo list */
7700 __mmplayer_video_stream_destroy_bo_list(player);
7701 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7703 if (player->profile.input_mem.buf) {
7704 free(player->profile.input_mem.buf);
7705 player->profile.input_mem.buf = NULL;
7707 player->profile.input_mem.len = 0;
7708 player->profile.input_mem.offset = 0;
7710 player->uri_info.uri_idx = 0;
7715 __mmplayer_check_subtitle(mm_player_t* player)
7717 MMHandleType attrs = 0;
7718 char *subtitle_uri = NULL;
7722 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7724 /* get subtitle attribute */
7725 attrs = MMPLAYER_GET_ATTRS(player);
7729 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7730 if (!subtitle_uri || !strlen(subtitle_uri))
7733 SECURE_LOGD("subtitle uri is %s[%d]", subtitle_uri, strlen(subtitle_uri));
7734 player->is_external_subtitle_present = TRUE;
7742 __mmplayer_cancel_eos_timer(mm_player_t* player)
7744 MMPLAYER_RETURN_IF_FAIL(player);
7746 if (player->eos_timer) {
7747 LOGD("cancel eos timer");
7748 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7749 player->eos_timer = 0;
7756 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
7760 MMPLAYER_RETURN_IF_FAIL(player);
7761 MMPLAYER_RETURN_IF_FAIL(sink);
7763 player->sink_elements =
7764 g_list_append(player->sink_elements, sink);
7770 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
7774 MMPLAYER_RETURN_IF_FAIL(player);
7775 MMPLAYER_RETURN_IF_FAIL(sink);
7777 player->sink_elements =
7778 g_list_remove(player->sink_elements, sink);
7784 __mmplayer_add_signal_connection(mm_player_t* player, GObject* object,
7785 MMPlayerSignalType type, const gchar* signal, GCallback cb_funct, gpointer u_data)
7787 MMPlayerSignalItem* item = NULL;
7790 MMPLAYER_RETURN_IF_FAIL(player);
7792 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7793 LOGE("invalid signal type [%d]", type);
7797 item = (MMPlayerSignalItem*)g_malloc(sizeof(MMPlayerSignalItem));
7799 LOGE("cannot connect signal [%s]", signal);
7804 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7805 player->signals[type] = g_list_append(player->signals[type], item);
7811 /* NOTE : be careful with calling this api. please refer to below glib comment
7812 * glib comment : Note that there is a bug in GObject that makes this function much
7813 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7814 * will no longer be called, but, the signal handler is not currently disconnected.
7815 * If the instance is itself being freed at the same time than this doesn't matter,
7816 * since the signal will automatically be removed, but if instance persists,
7817 * then the signal handler will leak. You should not remove the signal yourself
7818 * because in a future versions of GObject, the handler will automatically be
7821 * It's possible to work around this problem in a way that will continue to work
7822 * with future versions of GObject by checking that the signal handler is still
7823 * connected before disconnected it:
7825 * if (g_signal_handler_is_connected(instance, id))
7826 * g_signal_handler_disconnect(instance, id);
7829 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
7831 GList* sig_list = NULL;
7832 MMPlayerSignalItem* item = NULL;
7836 MMPLAYER_RETURN_IF_FAIL(player);
7838 LOGD("release signals type : %d", type);
7840 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7841 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7842 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7843 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7844 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7845 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7849 sig_list = player->signals[type];
7851 for (; sig_list; sig_list = sig_list->next) {
7852 item = sig_list->data;
7854 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7855 if (g_signal_handler_is_connected(item->obj, item->sig))
7856 g_signal_handler_disconnect(item->obj, item->sig);
7859 MMPLAYER_FREEIF(item);
7862 g_list_free(player->signals[type]);
7863 player->signals[type] = NULL;
7870 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7872 mm_player_t* player = 0;
7873 int prev_display_surface_type = 0;
7874 void *prev_display_overlay = NULL;
7878 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7879 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7881 player = MM_PLAYER_CAST(handle);
7883 /* check video sinkbin is created */
7884 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7885 LOGE("Videosink is already created");
7886 return MM_ERROR_NONE;
7889 LOGD("videosink element is not yet ready");
7891 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7892 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7894 return MM_ERROR_INVALID_ARGUMENT;
7897 /* load previous attributes */
7898 if (player->attrs) {
7899 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7900 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7901 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7902 if (prev_display_surface_type == surface_type) {
7903 LOGD("incoming display surface type is same as previous one, do nothing..");
7905 return MM_ERROR_NONE;
7908 LOGE("failed to load attributes");
7910 return MM_ERROR_PLAYER_INTERNAL;
7913 /* videobin is not created yet, so we just set attributes related to display surface */
7914 LOGD("store display attribute for given surface type(%d)", surface_type);
7915 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7916 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7917 if (mmf_attrs_commit(player->attrs)) {
7918 LOGE("failed to commit attribute");
7920 return MM_ERROR_PLAYER_INTERNAL;
7924 return MM_ERROR_NONE;
7927 /* Note : if silent is true, then subtitle would not be displayed. :*/
7928 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7930 mm_player_t* player = (mm_player_t*) hplayer;
7934 /* check player handle */
7935 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7937 player->set_mode.subtitle_off = silent;
7939 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
7943 return MM_ERROR_NONE;
7946 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
7948 MMPlayerGstElement* mainbin = NULL;
7949 MMPlayerGstElement* textbin = NULL;
7950 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7951 GstState current_state = GST_STATE_VOID_PENDING;
7952 GstState element_state = GST_STATE_VOID_PENDING;
7953 GstState element_pending_state = GST_STATE_VOID_PENDING;
7955 GstEvent *event = NULL;
7956 int result = MM_ERROR_NONE;
7958 GstClock *curr_clock = NULL;
7959 GstClockTime base_time, start_time, curr_time;
7964 /* check player handle */
7965 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7967 player->pipeline->mainbin &&
7968 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7970 mainbin = player->pipeline->mainbin;
7971 textbin = player->pipeline->textbin;
7973 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7975 // sync clock with current pipeline
7976 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7977 curr_time = gst_clock_get_time(curr_clock);
7979 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7980 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7982 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7983 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7985 if (current_state > GST_STATE_READY) {
7986 // sync state with current pipeline
7987 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7988 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7989 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7991 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7992 if (GST_STATE_CHANGE_FAILURE == ret) {
7993 LOGE("fail to state change.\n");
7994 result = MM_ERROR_PLAYER_INTERNAL;
7999 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8000 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8003 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8004 gst_object_unref(curr_clock);
8007 // seek to current position
8008 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8009 result = MM_ERROR_PLAYER_INVALID_STATE;
8010 LOGE("gst_element_query_position failed, invalid state\n");
8014 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8015 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);
8017 __mmplayer_gst_send_event_to_sink(player, event);
8019 result = MM_ERROR_PLAYER_INTERNAL;
8020 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8024 /* sync state with current pipeline */
8025 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8026 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8027 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8029 return MM_ERROR_NONE;
8032 /* release text pipeline resource */
8033 player->textsink_linked = 0;
8035 /* release signal */
8036 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8038 /* release textbin with it's childs */
8039 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8040 MMPLAYER_FREEIF(player->pipeline->textbin);
8041 player->pipeline->textbin = NULL;
8043 /* release subtitle elem */
8044 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8045 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8051 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
8053 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8054 GstState current_state = GST_STATE_VOID_PENDING;
8056 MMHandleType attrs = 0;
8057 MMPlayerGstElement* mainbin = NULL;
8058 MMPlayerGstElement* textbin = NULL;
8060 gchar* subtitle_uri = NULL;
8061 int result = MM_ERROR_NONE;
8062 const gchar *charset = NULL;
8066 /* check player handle */
8067 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8069 player->pipeline->mainbin &&
8070 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8071 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8073 mainbin = player->pipeline->mainbin;
8074 textbin = player->pipeline->textbin;
8076 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8077 if (current_state < GST_STATE_READY) {
8078 result = MM_ERROR_PLAYER_INVALID_STATE;
8079 LOGE("Pipeline is not in proper state\n");
8083 attrs = MMPLAYER_GET_ATTRS(player);
8085 LOGE("cannot get content attribute\n");
8086 result = MM_ERROR_PLAYER_INTERNAL;
8090 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8091 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8092 LOGE("subtitle uri is not proper filepath\n");
8093 result = MM_ERROR_PLAYER_INVALID_URI;
8097 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8098 LOGE("failed to get storage info of subtitle path");
8099 result = MM_ERROR_PLAYER_INVALID_URI;
8103 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
8104 LOGD("new subtitle file path is [%s]\n", filepath);
8106 if (!strcmp(filepath, subtitle_uri)) {
8107 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
8110 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8111 if (mmf_attrs_commit(player->attrs)) {
8112 LOGE("failed to commit.\n");
8117 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8118 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8119 player->subtitle_language_list = NULL;
8120 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8122 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8123 if (ret != GST_STATE_CHANGE_SUCCESS) {
8124 LOGE("failed to change state of textbin to READY");
8125 result = MM_ERROR_PLAYER_INTERNAL;
8129 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8130 if (ret != GST_STATE_CHANGE_SUCCESS) {
8131 LOGE("failed to change state of subparse to READY");
8132 result = MM_ERROR_PLAYER_INTERNAL;
8136 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8137 if (ret != GST_STATE_CHANGE_SUCCESS) {
8138 LOGE("failed to change state of filesrc to READY");
8139 result = MM_ERROR_PLAYER_INTERNAL;
8143 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8145 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8147 charset = util_get_charset(filepath);
8149 LOGD("detected charset is %s\n", charset);
8150 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8153 result = _mmplayer_sync_subtitle_pipeline(player);
8160 /* API to switch between external subtitles */
8161 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
8163 int result = MM_ERROR_NONE;
8164 mm_player_t* player = (mm_player_t*)hplayer;
8169 /* check player handle */
8170 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8172 /* filepath can be null in idle state */
8174 /* check file path */
8175 if ((path = strstr(filepath, "file://")))
8176 result = util_exist_file_path(path + 7);
8178 result = util_exist_file_path(filepath);
8180 if (result != MM_ERROR_NONE) {
8181 LOGE("invalid subtitle path 0x%X", result);
8182 return result; /* file not found or permission denied */
8186 if (!player->pipeline) {
8188 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8189 if (mmf_attrs_commit(player->attrs)) {
8190 LOGE("failed to commit"); /* subtitle path will not be created */
8191 return MM_ERROR_PLAYER_INTERNAL;
8194 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8195 /* check filepath */
8196 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8198 if (!__mmplayer_check_subtitle(player)) {
8199 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8200 if (mmf_attrs_commit(player->attrs)) {
8201 LOGE("failed to commit");
8202 return MM_ERROR_PLAYER_INTERNAL;
8205 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8206 LOGE("fail to create text pipeline");
8207 return MM_ERROR_PLAYER_INTERNAL;
8210 result = _mmplayer_sync_subtitle_pipeline(player);
8212 result = __mmplayer_change_external_subtitle_language(player, filepath);
8215 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8216 player->is_external_subtitle_added_now = TRUE;
8218 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8219 if (!player->subtitle_language_list) {
8220 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8221 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8222 LOGW("subtitle language list is not updated yet");
8224 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8232 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
8234 int result = MM_ERROR_NONE;
8235 gchar* change_pad_name = NULL;
8236 GstPad* sinkpad = NULL;
8237 MMPlayerGstElement* mainbin = NULL;
8238 enum MainElementID elem_idx = MMPLAYER_M_NUM;
8239 GstCaps* caps = NULL;
8240 gint total_track_num = 0;
8244 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8245 MM_ERROR_PLAYER_NOT_INITIALIZED);
8247 LOGD("Change Track(%d) to %d\n", type, index);
8249 mainbin = player->pipeline->mainbin;
8251 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8252 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8253 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8254 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8256 /* Changing Video Track is not supported. */
8257 LOGE("Track Type Error\n");
8261 if (mainbin[elem_idx].gst == NULL) {
8262 result = MM_ERROR_PLAYER_NO_OP;
8263 LOGD("Req track doesn't exist\n");
8267 total_track_num = player->selector[type].total_track_num;
8268 if (total_track_num <= 0) {
8269 result = MM_ERROR_PLAYER_NO_OP;
8270 LOGD("Language list is not available \n");
8274 if ((index < 0) || (index >= total_track_num)) {
8275 result = MM_ERROR_INVALID_ARGUMENT;
8276 LOGD("Not a proper index : %d \n", index);
8280 /*To get the new pad from the selector*/
8281 change_pad_name = g_strdup_printf("sink_%u", index);
8282 if (change_pad_name == NULL) {
8283 result = MM_ERROR_PLAYER_INTERNAL;
8284 LOGD("Pad does not exists\n");
8288 LOGD("new active pad name: %s\n", change_pad_name);
8290 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8291 if (sinkpad == NULL) {
8292 LOGD("sinkpad is NULL");
8293 result = MM_ERROR_PLAYER_INTERNAL;
8297 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
8298 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8300 caps = gst_pad_get_current_caps(sinkpad);
8301 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8304 gst_object_unref(sinkpad);
8306 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8307 __mmplayer_set_audio_attrs(player, caps);
8311 MMPLAYER_FREEIF(change_pad_name);
8315 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
8317 int result = MM_ERROR_NONE;
8318 mm_player_t* player = NULL;
8319 MMPlayerGstElement* mainbin = NULL;
8321 gint current_active_index = 0;
8323 GstState current_state = GST_STATE_VOID_PENDING;
8324 GstEvent* event = NULL;
8329 player = (mm_player_t*)hplayer;
8330 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8332 if (!player->pipeline) {
8333 LOGE("Track %d pre setting -> %d\n", type, index);
8335 player->selector[type].active_pad_index = index;
8339 mainbin = player->pipeline->mainbin;
8341 current_active_index = player->selector[type].active_pad_index;
8343 /*If index is same as running index no need to change the pad*/
8344 if (current_active_index == index)
8347 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8348 result = MM_ERROR_PLAYER_INVALID_STATE;
8352 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8353 if (current_state < GST_STATE_PAUSED) {
8354 result = MM_ERROR_PLAYER_INVALID_STATE;
8355 LOGW("Pipeline not in porper state\n");
8359 result = __mmplayer_change_selector_pad(player, type, index);
8360 if (result != MM_ERROR_NONE) {
8361 LOGE("change selector pad error\n");
8365 player->selector[type].active_pad_index = index;
8367 if (current_state == GST_STATE_PLAYING) {
8368 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);
8370 __mmplayer_gst_send_event_to_sink(player, event);
8372 result = MM_ERROR_PLAYER_INTERNAL;
8381 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
8383 mm_player_t* player = (mm_player_t*) hplayer;
8387 /* check player handle */
8388 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8390 *silent = player->set_mode.subtitle_off;
8392 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
8396 return MM_ERROR_NONE;
8400 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
8402 mm_player_t* player = (mm_player_t*) hplayer;
8404 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8406 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
8407 MMPLAYER_PRINT_STATE(player);
8408 LOGE("wrong-state : can't set the download mode to parse");
8409 return MM_ERROR_PLAYER_INVALID_STATE;
8412 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
8413 player->video_hub_download_mode = mode;
8415 return MM_ERROR_NONE;
8419 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
8421 mm_player_t* player = (mm_player_t*) hplayer;
8423 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8425 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
8426 player->sync_handler = enable;
8428 return MM_ERROR_NONE;
8432 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8434 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8435 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8437 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8438 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8442 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8443 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8444 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8445 mm_player_dump_t *dump_s;
8446 dump_s = g_malloc(sizeof(mm_player_dump_t));
8448 if (dump_s == NULL) {
8449 LOGE("malloc fail");
8453 dump_s->dump_element_file = NULL;
8454 dump_s->dump_pad = NULL;
8455 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8457 if (dump_s->dump_pad) {
8458 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
8459 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]);
8460 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8461 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);
8462 /* add list for removed buffer probe and close FILE */
8463 player->dump_list = g_list_append(player->dump_list, dump_s);
8464 LOGD("%s sink pad added buffer probe for dump", factory_name);
8469 LOGE("failed to get %s sink pad added", factory_name);
8478 static GstPadProbeReturn
8479 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8481 FILE *dump_data = (FILE *) u_data;
8483 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8484 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8486 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
8488 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8490 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8492 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8494 return GST_PAD_PROBE_OK;
8498 __mmplayer_release_dump_list(GList *dump_list)
8501 GList *d_list = dump_list;
8502 for (; d_list; d_list = g_list_next(d_list)) {
8503 mm_player_dump_t *dump_s = d_list->data;
8504 if (dump_s->dump_pad) {
8505 if (dump_s->probe_handle_id)
8506 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8508 if (dump_s->dump_element_file) {
8509 fclose(dump_s->dump_element_file);
8510 dump_s->dump_element_file = NULL;
8512 MMPLAYER_FREEIF(dump_s);
8514 g_list_free(dump_list);
8520 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
8522 mm_player_t* player = (mm_player_t*) hplayer;
8526 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8527 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8529 *exist = player->has_closed_caption;
8533 return MM_ERROR_NONE;
8536 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
8540 // LOGD("unref internal gst buffer %p", buffer);
8541 gst_buffer_unref((GstBuffer *)buffer);
8547 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8549 mm_player_t* player = (mm_player_t*) hplayer;
8553 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8554 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8556 if (MMPLAYER_IS_HTTP_PD(player))
8557 /* consider the timeout both download pipeline and playback pipeline */
8558 *timeout = player->ini.live_state_change_timeout + PLAYER_PD_STATE_CHANGE_TIME;
8559 else if (MMPLAYER_IS_STREAMING(player))
8560 *timeout = player->ini.live_state_change_timeout;
8562 *timeout = player->ini.localplayback_state_change_timeout;
8564 LOGD("timeout = %d\n", *timeout);
8567 return MM_ERROR_NONE;
8570 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8572 mm_player_t* player = (mm_player_t*) hplayer;
8576 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8577 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8579 *num = player->video_num_buffers;
8580 *extra_num = player->video_extra_num_buffers;
8582 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8585 return MM_ERROR_NONE;
8589 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
8593 MMPLAYER_RETURN_IF_FAIL(player);
8595 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8597 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8598 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8599 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8600 player->storage_info[i].id = -1;
8601 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8603 if (path_type != MMPLAYER_PATH_MAX)
8611 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8613 int ret = MM_ERROR_NONE;
8614 mm_player_t* player = (mm_player_t*)hplayer;
8615 MMMessageParamType msg_param = {0, };
8618 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8620 LOGW("state changed storage %d:%d", id, state);
8622 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8623 return MM_ERROR_NONE;
8625 /* FIXME: text path should be handled seperately. */
8626 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8627 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8628 LOGW("external storage is removed");
8630 if (player->msg_posted == FALSE) {
8631 memset(&msg_param, 0, sizeof(MMMessageParamType));
8632 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8633 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8634 player->msg_posted = TRUE;
8637 /* unrealize the player */
8638 ret = _mmplayer_unrealize(hplayer);
8639 if (ret != MM_ERROR_NONE)
8640 LOGE("failed to unrealize");
8647 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8649 int ret = MM_ERROR_NONE;
8650 mm_player_t* player = (mm_player_t*) hplayer;
8651 int idx = 0, total = 0;
8652 gchar *result = NULL, *tmp = NULL;
8655 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8656 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8658 total = *num = g_list_length(player->adaptive_info.var_list);
8660 LOGW("There is no stream variant info.");
8664 result = g_strdup("");
8665 for (idx = 0 ; idx < total ; idx++) {
8666 VariantData *v_data = NULL;
8667 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8670 gchar data[64] = {0};
8671 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8673 tmp = g_strconcat(result, data, NULL);
8677 LOGW("There is no variant data in %d", idx);
8682 *var_info = (char *)result;
8684 LOGD("variant info %d:%s", *num, *var_info);
8689 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8691 int ret = MM_ERROR_NONE;
8692 mm_player_t* player = (mm_player_t*) hplayer;
8695 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8697 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8699 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8700 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8701 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8703 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8704 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8705 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8706 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8708 /* FIXME: seek to current position for applying new variant limitation */
8716 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8718 int ret = MM_ERROR_NONE;
8719 mm_player_t* player = (mm_player_t*) hplayer;
8722 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8723 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8725 *bandwidth = player->adaptive_info.limit.bandwidth;
8726 *width = player->adaptive_info.limit.width;
8727 *height = player->adaptive_info.limit.height;
8729 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8735 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
8737 int ret = MM_ERROR_NONE;
8738 mm_player_t* player = (mm_player_t*) hplayer;
8741 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8743 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
8744 LOGW("buffer_ms will not be applied.");
8747 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
8749 if (player->streamer == NULL) {
8750 player->streamer = __mm_player_streaming_create();
8751 __mm_player_streaming_initialize(player->streamer);
8755 player->streamer->buffering_req.prebuffer_time = buffer_ms;
8757 if (rebuffer_ms >= 0)
8758 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
8765 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
8767 int ret = MM_ERROR_NONE;
8768 mm_player_t* player = (mm_player_t*) hplayer;
8771 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8772 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8774 if (player->streamer == NULL) {
8775 player->streamer = __mm_player_streaming_create();
8776 __mm_player_streaming_initialize(player->streamer);
8779 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
8780 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8782 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
8788 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8790 #define IDX_FIRST_SW_CODEC 0
8791 mm_player_t* player = (mm_player_t*) hplayer;
8792 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8793 MMHandleType attrs = 0;
8796 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8798 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8799 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8800 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8802 switch (stream_type) {
8803 case MM_PLAYER_STREAM_TYPE_AUDIO:
8804 /* to support audio codec selection, codec info have to be added in ini file as below.
8805 audio codec element hw = xxxx
8806 audio codec element sw = avdec */
8807 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8808 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8809 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8810 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8811 LOGE("There is no audio codec info for codec_type %d", codec_type);
8812 return MM_ERROR_PLAYER_NO_OP;
8815 case MM_PLAYER_STREAM_TYPE_VIDEO:
8816 /* to support video codec selection, codec info have to be added in ini file as below.
8817 video codec element hw = omx
8818 video codec element sw = avdec */
8819 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8820 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8821 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8822 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8823 LOGE("There is no video codec info for codec_type %d", codec_type);
8824 return MM_ERROR_PLAYER_NO_OP;
8828 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8829 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8833 LOGD("update %s codec_type to %d", attr_name, codec_type);
8835 attrs = MMPLAYER_GET_ATTRS(player);
8836 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8838 if (mmf_attrs_commit(player->attrs)) {
8839 LOGE("failed to commit codec_type attributes");
8840 return MM_ERROR_PLAYER_INTERNAL;
8844 return MM_ERROR_NONE;
8848 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8850 mm_player_t* player = (mm_player_t*) hplayer;
8851 GstElement* rg_vol_element = NULL;
8855 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8857 player->sound.rg_enable = enabled;
8859 /* just hold rgvolume enable value if pipeline is not ready */
8860 if (!player->pipeline || !player->pipeline->audiobin) {
8861 LOGD("pipeline is not ready. holding rgvolume enable value\n");
8862 return MM_ERROR_NONE;
8865 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8867 if (!rg_vol_element) {
8868 LOGD("rgvolume element is not created");
8869 return MM_ERROR_PLAYER_INTERNAL;
8873 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8875 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8879 return MM_ERROR_NONE;
8883 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8885 mm_player_t* player = (mm_player_t*) hplayer;
8886 GstElement* rg_vol_element = NULL;
8887 gboolean enable = FALSE;
8891 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8892 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8894 /* just hold enable_rg value if pipeline is not ready */
8895 if (!player->pipeline || !player->pipeline->audiobin) {
8896 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
8897 *enabled = player->sound.rg_enable;
8898 return MM_ERROR_NONE;
8901 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8903 if (!rg_vol_element) {
8904 LOGD("rgvolume element is not created");
8905 return MM_ERROR_PLAYER_INTERNAL;
8908 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8913 return MM_ERROR_NONE;
8917 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8919 mm_player_t* player = (mm_player_t*) hplayer;
8920 MMHandleType attrs = 0;
8921 void *handle = NULL;
8922 int ret = MM_ERROR_NONE;
8926 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8928 attrs = MMPLAYER_GET_ATTRS(player);
8929 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8931 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8933 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8934 return MM_ERROR_PLAYER_INTERNAL;
8937 player->video_roi.scale_x = scale_x;
8938 player->video_roi.scale_y = scale_y;
8939 player->video_roi.scale_width = scale_width;
8940 player->video_roi.scale_height = scale_height;
8942 /* check video sinkbin is created */
8943 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8944 return MM_ERROR_NONE;
8946 if (!gst_video_overlay_set_video_roi_area(
8947 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8948 scale_x, scale_y, scale_width, scale_height))
8949 ret = MM_ERROR_PLAYER_INTERNAL;
8951 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8952 scale_x, scale_y, scale_width, scale_height);
8960 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8962 mm_player_t* player = (mm_player_t*) hplayer;
8963 int ret = MM_ERROR_NONE;
8967 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8968 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8970 *scale_x = player->video_roi.scale_x;
8971 *scale_y = player->video_roi.scale_y;
8972 *scale_width = player->video_roi.scale_width;
8973 *scale_height = player->video_roi.scale_height;
8975 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8976 *scale_x, *scale_y, *scale_width, *scale_height);
8982 __mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs)
8984 gboolean ret = FALSE;
8985 gint64 dur_nsec = 0;
8986 LOGD("try to update duration");
8988 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8989 player->duration = dur_nsec;
8990 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8994 if (player->duration < 0) {
8995 LOGW("duration is Non-Initialized !!!");
8996 player->duration = 0;
8999 /* update streaming service type */
9000 player->streaming_type = __mmplayer_get_stream_service_type(player);
9002 /* check duration is OK */
9003 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
9004 /* FIXIT : find another way to get duration here. */
9005 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9012 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
9014 /* update audio params
9015 NOTE : We need original audio params and it can be only obtained from src pad of audio
9016 decoder. Below code only valid when we are not using 'resampler' just before
9017 'audioconverter'. */
9018 GstCaps *caps_a = NULL;
9020 gint samplerate = 0, channels = 0;
9021 GstStructure* p = NULL;
9023 LOGD("try to update audio attrs");
9025 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9026 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
9028 pad = gst_element_get_static_pad(
9029 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
9032 LOGW("failed to get pad from audiosink");
9036 caps_a = gst_pad_get_current_caps(pad);
9039 LOGW("not ready to get audio caps");
9040 gst_object_unref(pad);
9044 p = gst_caps_get_structure(caps_a, 0);
9046 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9048 gst_structure_get_int(p, "rate", &samplerate);
9049 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
9051 gst_structure_get_int(p, "channels", &channels);
9052 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
9054 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9056 gst_caps_unref(caps_a);
9057 gst_object_unref(pad);
9063 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
9065 LOGD("try to update video attrs");
9067 GstCaps *caps_v = NULL;
9071 GstStructure* p = NULL;
9073 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9074 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9076 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9078 LOGD("no videosink sink pad");
9082 caps_v = gst_pad_get_current_caps(pad);
9083 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9084 if (!caps_v && player->v_stream_caps) {
9085 caps_v = player->v_stream_caps;
9086 gst_caps_ref(caps_v);
9090 LOGD("no negitiated caps from videosink");
9091 gst_object_unref(pad);
9095 p = gst_caps_get_structure(caps_v, 0);
9096 gst_structure_get_int(p, "width", &width);
9097 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
9099 gst_structure_get_int(p, "height", &height);
9100 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
9102 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9104 SECURE_LOGD("width : %d height : %d", width, height);
9106 gst_caps_unref(caps_v);
9107 gst_object_unref(pad);
9110 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
9111 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9118 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
9120 gboolean ret = FALSE;
9121 guint64 data_size = 0;
9125 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9126 if (!player->duration)
9129 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9130 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9131 if (stat(path, &sb) == 0)
9132 data_size = (guint64)sb.st_size;
9134 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9135 data_size = player->http_content_size;
9138 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9141 guint64 bitrate = 0;
9142 guint64 msec_dur = 0;
9144 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9146 bitrate = data_size * 8 * 1000 / msec_dur;
9147 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
9148 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
9152 LOGD("player duration is less than 0");
9156 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9157 if (player->total_bitrate) {
9158 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
9166 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile* data, const char *uri, int uri_type)
9168 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9169 data->uri_type = uri_type;
9172 __mmplayer_set_mem_uri(MMPlayerParseProfile* data, char *path, void *param)
9174 int ret = MM_ERROR_PLAYER_INVALID_URI;
9176 char *buffer = NULL;
9177 char *seperator = strchr(path, ',');
9178 char ext[100] = {0,}, size[100] = {0,};
9181 if ((buffer = strstr(path, "ext="))) {
9182 buffer += strlen("ext=");
9184 if (strlen(buffer)) {
9185 strncpy(ext, buffer, 99);
9187 if ((seperator = strchr(ext, ','))
9188 || (seperator = strchr(ext, ' '))
9189 || (seperator = strchr(ext, '\0'))) {
9190 seperator[0] = '\0';
9195 if ((buffer = strstr(path, "size="))) {
9196 buffer += strlen("size=");
9198 if (strlen(buffer) > 0) {
9199 strncpy(size, buffer, 99);
9201 if ((seperator = strchr(size, ','))
9202 || (seperator = strchr(size, ' '))
9203 || (seperator = strchr(size, '\0'))) {
9204 seperator[0] = '\0';
9207 mem_size = atoi(size);
9212 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
9214 if (mem_size && param) {
9215 if (data->input_mem.buf)
9216 free(data->input_mem.buf);
9217 data->input_mem.buf = malloc(mem_size);
9219 if (data->input_mem.buf) {
9220 memcpy(data->input_mem.buf, param, mem_size);
9221 data->input_mem.len = mem_size;
9222 ret = MM_ERROR_NONE;
9224 LOGE("failed to alloc mem %d", mem_size);
9225 ret = MM_ERROR_PLAYER_INTERNAL;
9228 data->input_mem.offset = 0;
9229 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9236 __mmplayer_set_file_uri(MMPlayerParseProfile* data, const char *uri)
9238 gchar *location = NULL;
9241 int ret = MM_ERROR_NONE;
9243 if ((path = strstr(uri, "file://"))) {
9244 location = g_filename_from_uri(uri, NULL, &err);
9245 if (!location || (err != NULL)) {
9246 LOGE("Invalid URI '%s' for filesrc: %s", path,
9247 (err != NULL) ? err->message : "unknown error");
9253 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9254 return MM_ERROR_PLAYER_INVALID_URI;
9256 LOGD("path from uri: %s", location);
9259 path = (location != NULL) ? (location) : ((char *)uri);
9262 ret = util_exist_file_path(path);
9264 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9265 if (ret == MM_ERROR_NONE) {
9266 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9267 if (util_is_sdp_file(path)) {
9268 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
9269 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9271 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9273 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9274 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9276 LOGE("invalid uri, could not play..\n");
9277 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9286 static MMPlayerVideoStreamDataType*
9287 __mmplayer_create_stream_from_pad(GstPad *pad)
9289 GstCaps *caps = NULL;
9290 GstStructure *structure = NULL;
9291 unsigned int fourcc = 0;
9292 const gchar *string_format = NULL;
9293 MMPlayerVideoStreamDataType *stream = NULL;
9295 MMPixelFormatType format;
9297 caps = gst_pad_get_current_caps(pad);
9299 LOGE("Caps is NULL.");
9303 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9304 structure = gst_caps_get_structure(caps, 0);
9305 gst_structure_get_int(structure, "width", &width);
9306 gst_structure_get_int(structure, "height", &height);
9307 string_format = gst_structure_get_string(structure, "format");
9309 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9310 format = util_get_pixtype(fourcc);
9311 gst_caps_unref(caps);
9314 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9315 LOGE("Wrong condition!!");
9319 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
9321 LOGE("failed to alloc mem for video data");
9325 stream->width = width;
9326 stream->height = height;
9327 stream->format = format;
9333 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9335 unsigned int pitch = 0;
9337 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9339 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9340 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
9341 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
9342 stream->stride[index] = pitch;
9343 stream->elevation[index] = stream->height;
9348 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
9350 if (stream->format == MM_PIXEL_FORMAT_I420) {
9351 int ret = TBM_SURFACE_ERROR_NONE;
9352 tbm_surface_h surface;
9353 tbm_surface_info_s info;
9355 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9357 ret = tbm_surface_get_info(surface, &info);
9358 if (ret != TBM_SURFACE_ERROR_NONE) {
9359 tbm_surface_destroy(surface);
9363 tbm_surface_destroy(surface);
9364 stream->stride[0] = info.planes[0].stride;
9365 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9366 stream->stride[1] = info.planes[1].stride;
9367 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9368 stream->stride[2] = info.planes[2].stride;
9369 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9370 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9371 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9372 stream->stride[0] = stream->width * 4;
9373 stream->elevation[0] = stream->height;
9374 stream->bo_size = stream->stride[0] * stream->height;
9376 LOGE("Not support format %d", stream->format);
9384 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9386 tbm_bo_handle thandle;
9388 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9389 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9390 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9394 unsigned char *src = NULL;
9395 unsigned char *dest = NULL;
9396 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9398 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9400 LOGE("fail to gst_memory_map");
9404 if (!mapinfo.data) {
9405 LOGE("data pointer is wrong");
9409 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9410 if (!stream->bo[0]) {
9411 LOGE("Fail to tbm_bo_alloc!!");
9415 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9417 LOGE("thandle pointer is wrong");
9421 if (stream->format == MM_PIXEL_FORMAT_I420) {
9422 src_stride[0] = GST_ROUND_UP_4(stream->width);
9423 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9424 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9425 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9428 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9429 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9431 for (i = 0; i < 3; i++) {
9432 src = mapinfo.data + src_offset[i];
9433 dest = thandle.ptr + dest_offset[i];
9438 for (j = 0; j < stream->height >> k; j++) {
9439 memcpy(dest, src, stream->width>>k);
9440 src += src_stride[i];
9441 dest += stream->stride[i];
9444 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9445 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9447 LOGE("Not support format %d", stream->format);
9451 tbm_bo_unmap(stream->bo[0]);
9452 gst_memory_unmap(mem, &mapinfo);
9458 tbm_bo_unmap(stream->bo[0]);
9461 gst_memory_unmap(mem, &mapinfo);