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>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.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
92 #define PLAYER_DISPLAY_MODE_DST_ROI 5
94 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
96 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
97 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
98 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
99 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
101 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
102 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
104 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
106 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
107 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
108 #define DEFAULT_PCM_OUT_CHANNEL 2
110 /*---------------------------------------------------------------------------
111 | LOCAL CONSTANT DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
114 /*---------------------------------------------------------------------------
115 | LOCAL DATA TYPE DEFINITIONS: |
116 ---------------------------------------------------------------------------*/
117 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
118 We are defining our own and will be removed when it actually exposed */
120 GST_AUTOPLUG_SELECT_TRY,
121 GST_AUTOPLUG_SELECT_EXPOSE,
122 GST_AUTOPLUG_SELECT_SKIP
123 } GstAutoplugSelectResult;
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(mmplayer_t *player);
138 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
141 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
142 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
143 static void __mmplayer_gst_create_sink_bin(GstElement *decodebin, GstPad *pad, GstCaps *ref_caps, gpointer data);
144 static gboolean __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps);
145 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
146 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
148 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
149 static void __mmplayer_release_misc(mmplayer_t *player);
150 static void __mmplayer_release_misc_post(mmplayer_t *player);
151 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
152 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
153 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
154 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
155 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
157 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
158 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
159 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
160 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
161 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
162 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
163 static gpointer __mmplayer_gapless_play_thread(gpointer data);
164 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
165 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
166 static void __mmplayer_release_dump_list(GList *dump_list);
167 static int __mmplayer_gst_realize(mmplayer_t *player);
168 static int __mmplayer_gst_unrealize(mmplayer_t *player);
169 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
170 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
173 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
174 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player);
175 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
176 static gboolean __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type);
177 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
178 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
179 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
180 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
181 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
182 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
183 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
184 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
185 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
186 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
188 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
189 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
190 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
192 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
193 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
194 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
195 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
197 static void __mmplayer_set_pause_state(mmplayer_t *player);
198 static void __mmplayer_set_playing_state(mmplayer_t *player);
199 /*===========================================================================================
201 | FUNCTION DEFINITIONS |
203 ========================================================================================== */
205 /* This function should be called after the pipeline goes PAUSED or higher
208 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
210 static gboolean has_duration = FALSE;
211 static gboolean has_video_attrs = FALSE;
212 static gboolean has_audio_attrs = FALSE;
213 static gboolean has_bitrate = FALSE;
214 gboolean missing_only = FALSE;
215 gboolean all = FALSE;
216 MMHandleType attrs = 0;
220 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
222 /* check player state here */
223 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
224 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
225 /* give warning now only */
226 LOGW("be careful. content attributes may not available in this state ");
229 /* get content attribute first */
230 attrs = MMPLAYER_GET_ATTRS(player);
232 LOGE("cannot get content attribute");
236 /* get update flag */
238 if (flag & ATTR_MISSING_ONLY) {
240 LOGD("updating missed attr only");
243 if (flag & ATTR_ALL) {
245 has_duration = FALSE;
246 has_video_attrs = FALSE;
247 has_audio_attrs = FALSE;
250 LOGD("updating all attrs");
253 if (missing_only && all) {
254 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
255 missing_only = FALSE;
258 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
259 has_duration = __mmplayer_update_duration_value(player);
261 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
262 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
264 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
265 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
267 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
268 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
276 _mmplayer_get_stream_service_type(mmplayer_t *player)
278 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
282 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
284 player->pipeline->mainbin &&
285 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
286 STREAMING_SERVICE_NONE);
288 /* streaming service type if streaming */
289 if (!MMPLAYER_IS_STREAMING(player))
290 return STREAMING_SERVICE_NONE;
292 streaming_type = (player->duration == 0) ?
293 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
295 switch (streaming_type) {
296 case STREAMING_SERVICE_LIVE:
297 LOGD("it's live streaming");
299 case STREAMING_SERVICE_VOD:
300 LOGD("it's vod streaming");
303 LOGE("should not get here");
309 return streaming_type;
312 /* this function sets the player state and also report
313 * it to applicaton by calling callback function
316 _mmplayer_set_state(mmplayer_t *player, int state)
318 MMMessageParamType msg = {0, };
320 MMPLAYER_RETURN_IF_FAIL(player);
322 if (MMPLAYER_CURRENT_STATE(player) == state) {
323 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
324 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
328 /* update player states */
329 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
330 MMPLAYER_CURRENT_STATE(player) = state;
332 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
333 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
336 MMPLAYER_PRINT_STATE(player);
338 switch (MMPLAYER_CURRENT_STATE(player)) {
339 case MM_PLAYER_STATE_NULL:
340 case MM_PLAYER_STATE_READY:
342 case MM_PLAYER_STATE_PAUSED:
343 __mmplayer_set_pause_state(player);
345 case MM_PLAYER_STATE_PLAYING:
346 __mmplayer_set_playing_state(player);
348 case MM_PLAYER_STATE_NONE:
350 LOGW("invalid target state, there is nothing to do.");
355 /* post message to application */
356 if (MMPLAYER_TARGET_STATE(player) == state) {
357 /* fill the message with state of player */
358 msg.union_type = MM_MSG_UNION_STATE;
359 msg.state.previous = MMPLAYER_PREV_STATE(player);
360 msg.state.current = MMPLAYER_CURRENT_STATE(player);
362 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
364 /* state changed by resource callback */
365 if (player->interrupted_by_resource)
366 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
367 else /* state changed by usecase */
368 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
371 LOGD("intermediate state, do nothing.");
372 MMPLAYER_PRINT_STATE(player);
376 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
377 && !player->sent_bos) {
378 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
379 player->sent_bos = TRUE;
386 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
388 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
389 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
391 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
393 LOGD("incomming command : %d ", command);
395 current_state = MMPLAYER_CURRENT_STATE(player);
396 pending_state = MMPLAYER_PENDING_STATE(player);
398 MMPLAYER_PRINT_STATE(player);
401 case MMPLAYER_COMMAND_CREATE:
403 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
405 if (current_state == MM_PLAYER_STATE_NULL ||
406 current_state == MM_PLAYER_STATE_READY ||
407 current_state == MM_PLAYER_STATE_PAUSED ||
408 current_state == MM_PLAYER_STATE_PLAYING)
413 case MMPLAYER_COMMAND_DESTROY:
415 /* destroy can called anytime */
417 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
421 case MMPLAYER_COMMAND_REALIZE:
423 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
425 if (pending_state != MM_PLAYER_STATE_NONE) {
428 /* need ready state to realize */
429 if (current_state == MM_PLAYER_STATE_READY)
432 if (current_state != MM_PLAYER_STATE_NULL)
438 case MMPLAYER_COMMAND_UNREALIZE:
440 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
442 if (current_state == MM_PLAYER_STATE_NULL)
447 case MMPLAYER_COMMAND_START:
449 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
451 if (pending_state == MM_PLAYER_STATE_NONE) {
452 if (current_state == MM_PLAYER_STATE_PLAYING)
454 else if (current_state != MM_PLAYER_STATE_READY &&
455 current_state != MM_PLAYER_STATE_PAUSED)
457 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
459 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
460 LOGD("player is going to paused state, just change the pending state as playing");
467 case MMPLAYER_COMMAND_STOP:
469 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
471 if (current_state == MM_PLAYER_STATE_READY)
474 /* need playing/paused state to stop */
475 if (current_state != MM_PLAYER_STATE_PLAYING &&
476 current_state != MM_PLAYER_STATE_PAUSED)
481 case MMPLAYER_COMMAND_PAUSE:
483 if (MMPLAYER_IS_LIVE_STREAMING(player))
486 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
487 goto NOT_COMPLETED_SEEK;
489 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
491 if (pending_state == MM_PLAYER_STATE_NONE) {
492 if (current_state == MM_PLAYER_STATE_PAUSED)
494 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
496 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
498 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
499 if (current_state == MM_PLAYER_STATE_PAUSED)
500 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
507 case MMPLAYER_COMMAND_RESUME:
509 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
510 goto NOT_COMPLETED_SEEK;
512 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
514 if (pending_state == MM_PLAYER_STATE_NONE) {
515 if (current_state == MM_PLAYER_STATE_PLAYING)
517 else if (current_state != MM_PLAYER_STATE_PAUSED)
519 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
521 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
522 LOGD("player is going to paused state, just change the pending state as playing");
532 player->cmd = command;
534 return MM_ERROR_NONE;
537 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
538 MMPLAYER_STATE_GET_NAME(current_state), command);
539 return MM_ERROR_PLAYER_INVALID_STATE;
542 LOGW("not completed seek");
543 return MM_ERROR_PLAYER_DOING_SEEK;
546 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
547 return MM_ERROR_PLAYER_NO_OP;
550 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
551 return MM_ERROR_PLAYER_NO_OP;
554 int _mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
556 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
557 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
560 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
561 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
563 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
564 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
566 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
567 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
570 LOGE("invalid mmplayer resource type %d", type);
571 return MM_ERROR_PLAYER_INTERNAL;
574 if (player->hw_resource[type] != NULL) {
575 LOGD("[%d type] resource was already acquired", type);
576 return MM_ERROR_NONE;
579 LOGD("mark for acquire [%d type] resource", type);
580 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
581 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
582 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
583 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
584 return MM_ERROR_PLAYER_INTERNAL;
587 rm_ret = mm_resource_manager_commit(player->resource_manager);
588 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
589 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
590 return MM_ERROR_PLAYER_INTERNAL;
594 return MM_ERROR_NONE;
597 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
599 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
603 if (player->hw_resource[type] == NULL) {
604 LOGD("there is no acquired [%d type] resource", type);
605 return MM_ERROR_NONE;
608 LOGD("mark for release [%d type] resource", type);
609 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
610 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
611 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
612 return MM_ERROR_PLAYER_INTERNAL;
615 player->hw_resource[type] = NULL;
617 rm_ret = mm_resource_manager_commit(player->resource_manager);
618 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
619 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
620 return MM_ERROR_PLAYER_INTERNAL;
624 return MM_ERROR_NONE;
628 __mmplayer_initialize_gapless_play(mmplayer_t *player)
634 player->smooth_streaming = FALSE;
635 player->videodec_linked = 0;
636 player->audiodec_linked = 0;
637 player->textsink_linked = 0;
638 player->is_external_subtitle_present = FALSE;
639 player->is_external_subtitle_added_now = FALSE;
640 player->not_supported_codec = MISSING_PLUGIN_NONE;
641 player->can_support_codec = FOUND_PLUGIN_NONE;
642 player->pending_seek.is_pending = false;
643 player->pending_seek.pos = 0;
644 player->msg_posted = FALSE;
645 player->has_many_types = FALSE;
646 player->no_more_pad = FALSE;
647 player->not_found_demuxer = 0;
648 player->seek_state = MMPLAYER_SEEK_NONE;
649 player->is_subtitle_force_drop = FALSE;
650 player->play_subtitle = FALSE;
651 player->adjust_subtitle_pos = 0;
653 player->total_bitrate = 0;
654 player->total_maximum_bitrate = 0;
656 _mmplayer_track_initialize(player);
657 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
659 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
660 player->bitrate[i] = 0;
661 player->maximum_bitrate[i] = 0;
664 if (player->v_stream_caps) {
665 gst_caps_unref(player->v_stream_caps);
666 player->v_stream_caps = NULL;
669 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
671 /* clean found audio decoders */
672 if (player->audio_decoders) {
673 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
674 player->audio_decoders = NULL;
677 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
682 void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state)
684 LOGI("set pipeline reconfigure state %d", state);
685 MMPLAYER_RECONFIGURE_LOCK(player);
686 player->gapless.reconfigure = state;
687 if (!state) /* wake up the waiting job */
688 MMPLAYER_RECONFIGURE_SIGNAL(player);
689 MMPLAYER_RECONFIGURE_UNLOCK(player);
693 __mmplayer_gapless_play_thread(gpointer data)
695 mmplayer_t *player = (mmplayer_t *)data;
696 mmplayer_gst_element_t *mainbin = NULL;
698 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
700 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
701 while (!player->gapless_play_thread_exit) {
702 LOGD("gapless play thread started. waiting for signal.");
703 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
705 LOGD("reconfigure pipeline for gapless play.");
707 if (player->gapless_play_thread_exit) {
708 _mmplayer_set_reconfigure_state(player, FALSE);
709 LOGD("exiting gapless play thread");
713 mainbin = player->pipeline->mainbin;
715 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
716 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
717 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
718 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
719 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
721 /* Initialize Player values */
722 __mmplayer_initialize_gapless_play(player);
724 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
726 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
732 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
734 GSource *source = NULL;
738 source = g_main_context_find_source_by_id(context, source_id);
739 if (source != NULL) {
740 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
741 g_source_destroy(source);
748 _mmplayer_watcher_removed_notify(gpointer data)
750 mmplayer_t *player = (mmplayer_t *)data;
751 MMPLAYER_RETURN_IF_FAIL(player);
753 MMPLAYER_BUS_WATCHER_LOCK(player);
754 player->bus_watcher = 0;
755 MMPLAYER_BUS_WATCHER_SIGNAL(player);
756 MMPLAYER_BUS_WATCHER_UNLOCK(player);
760 _mmplayer_bus_watcher_remove(MMHandleType hplayer)
762 mmplayer_t *player = (mmplayer_t *)hplayer;
765 MMPLAYER_RETURN_IF_FAIL(player);
767 /* disconnecting bus watch */
768 if (player->bus_watcher > 0) {
769 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
770 MMPLAYER_BUS_WATCHER_LOCK(player);
771 end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND;
772 while (player->bus_watcher > 0)
773 MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time);
774 MMPLAYER_BUS_WATCHER_UNLOCK(player);
776 g_mutex_clear(&player->bus_watcher_mutex);
777 g_cond_clear(&player->bus_watcher_cond);
784 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
786 mmplayer_t *player = (mmplayer_t *)hplayer;
787 GstMessage *msg = NULL;
788 GQueue *queue = NULL;
791 MMPLAYER_RETURN_IF_FAIL(player);
793 /* destroy the gst bus msg thread */
794 if (player->bus_msg_thread) {
795 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
796 player->bus_msg_thread_exit = TRUE;
797 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
798 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
800 LOGD("gst bus msg thread exit.");
801 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
802 player->bus_msg_thread = NULL;
804 g_mutex_clear(&player->bus_msg_thread_mutex);
805 g_cond_clear(&player->bus_msg_thread_cond);
808 g_mutex_lock(&player->bus_msg_q_lock);
809 queue = player->bus_msg_q;
810 while (!g_queue_is_empty(queue)) {
811 msg = (GstMessage *)g_queue_pop_head(queue);
816 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
817 gst_message_unref(msg);
819 g_mutex_unlock(&player->bus_msg_q_lock);
825 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
827 GstElement *parent = NULL;
829 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
830 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
833 MMPLAYER_FSINK_LOCK(player);
835 /* get parent of fakesink */
836 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
838 LOGD("fakesink already removed");
842 gst_element_set_locked_state(fakesink->gst, TRUE);
844 /* setting the state to NULL never returns async
845 * so no need to wait for completion of state transiton
847 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
848 LOGE("fakesink state change failure!");
849 /* FIXIT : should I return here? or try to proceed to next? */
852 /* remove fakesink from it's parent */
853 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
854 LOGE("failed to remove fakesink");
856 gst_object_unref(parent);
861 gst_object_unref(parent);
863 LOGD("state-holder removed");
865 gst_element_set_locked_state(fakesink->gst, FALSE);
867 MMPLAYER_FSINK_UNLOCK(player);
872 gst_element_set_locked_state(fakesink->gst, FALSE);
874 MMPLAYER_FSINK_UNLOCK(player);
878 static GstPadProbeReturn
879 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
881 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
882 return GST_PAD_PROBE_OK;
886 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
888 gint64 stop_running_time = 0;
889 gint64 position_running_time = 0;
893 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
894 if ((player->gapless.update_segment[idx] == TRUE) ||
895 !(player->track[idx].event_probe_id)) {
897 LOGW("[%d] skip", idx);
902 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
904 gst_segment_to_running_time(&player->gapless.segment[idx],
905 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
906 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
908 gst_segment_to_running_time(&player->gapless.segment[idx],
909 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
911 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
913 gst_segment_to_running_time(&player->gapless.segment[idx],
914 GST_FORMAT_TIME, player->duration);
917 position_running_time =
918 gst_segment_to_running_time(&player->gapless.segment[idx],
919 GST_FORMAT_TIME, player->gapless.segment[idx].position);
921 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
922 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
924 GST_TIME_ARGS(stop_running_time),
925 GST_TIME_ARGS(position_running_time),
926 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
927 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
929 position_running_time = MAX(position_running_time, stop_running_time);
930 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
931 GST_FORMAT_TIME, player->gapless.segment[idx].start);
932 position_running_time = MAX(0, position_running_time);
933 position = MAX(position, position_running_time);
937 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
938 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
939 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
941 player->gapless.start_time[stream_type] += position;
947 static GstPadProbeReturn
948 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
950 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
951 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
952 mmplayer_t *player = (mmplayer_t *)data;
953 GstCaps *caps = NULL;
954 GstStructure *str = NULL;
955 const gchar *name = NULL;
956 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
957 gboolean caps_ret = TRUE;
959 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
960 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
961 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
962 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
963 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
966 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
970 if (strstr(name, "audio")) {
971 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
972 } else if (strstr(name, "video")) {
973 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
975 /* text track is not supportable */
976 LOGE("invalid name %s", name);
980 switch (GST_EVENT_TYPE(event)) {
983 /* in case of gapless, drop eos event not to send it to sink */
984 if (player->gapless.reconfigure && !player->msg_posted) {
985 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
986 ret = GST_PAD_PROBE_DROP;
990 case GST_EVENT_STREAM_START:
992 __mmplayer_gst_selector_update_start_time(player, stream_type);
995 case GST_EVENT_FLUSH_STOP:
997 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
998 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
999 player->gapless.start_time[stream_type] = 0;
1002 case GST_EVENT_SEGMENT:
1007 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1008 gst_event_copy_segment(event, &segment);
1010 if (segment.format != GST_FORMAT_TIME)
1013 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1014 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1015 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1016 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1017 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1018 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1020 /* keep the all the segment ev to cover the seeking */
1021 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1022 player->gapless.update_segment[stream_type] = TRUE;
1024 if (!player->gapless.running)
1027 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1029 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1031 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1032 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1033 gst_event_unref(event);
1034 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1040 gdouble proportion = 0.0;
1041 GstClockTimeDiff diff = 0;
1042 GstClockTime timestamp = 0;
1043 gint64 running_time_diff = -1;
1044 GstQOSType type = 0;
1045 GstEvent *tmpev = NULL;
1047 running_time_diff = player->gapless.segment[stream_type].base;
1049 if (running_time_diff <= 0) /* don't need to adjust */
1052 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1053 gst_event_unref(event);
1055 if (timestamp < running_time_diff) {
1056 LOGW("QOS event from previous group");
1057 ret = GST_PAD_PROBE_DROP;
1062 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1063 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1064 stream_type, GST_TIME_ARGS(timestamp),
1065 GST_TIME_ARGS(running_time_diff),
1066 GST_TIME_ARGS(timestamp - running_time_diff));
1069 timestamp -= running_time_diff;
1071 /* That case is invalid for QoS events */
1072 if (diff < 0 && -diff > timestamp) {
1073 LOGW("QOS event from previous group");
1074 ret = GST_PAD_PROBE_DROP;
1078 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1079 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1089 gst_caps_unref(caps);
1093 /* create fakesink for audio or video path witout audiobin or videobin */
1095 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1097 GstElement *pipeline = NULL;
1098 GstElement *fakesink = NULL;
1099 GstPad *sinkpad = NULL;
1102 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1104 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1107 fakesink = gst_element_factory_make("fakesink", NULL);
1108 if (fakesink == NULL) {
1109 LOGE("failed to create fakesink");
1113 /* store it as it's sink element */
1114 __mmplayer_add_sink(player, fakesink);
1116 gst_bin_add(GST_BIN(pipeline), fakesink);
1119 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1121 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1123 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1124 LOGE("failed to link fakesink");
1125 gst_object_unref(GST_OBJECT(fakesink));
1129 if (strstr(name, "video")) {
1130 if (player->v_stream_caps) {
1131 gst_caps_unref(player->v_stream_caps);
1132 player->v_stream_caps = NULL;
1134 if (player->ini.set_dump_element_flag)
1135 __mmplayer_add_dump_buffer_probe(player, fakesink);
1138 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1139 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1143 gst_object_unref(GST_OBJECT(sinkpad));
1150 __mmplayer_gst_make_concat(mmplayer_t *player, main_element_id_e elem_idx)
1152 GstElement *pipeline = NULL;
1153 GstElement *concat = NULL;
1156 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1158 concat = gst_element_factory_make("concat", NULL);
1160 LOGE("failed to create concat");
1164 LOGD("Create concat [%d] element", elem_idx);
1166 player->pipeline->mainbin[elem_idx].id = elem_idx;
1167 player->pipeline->mainbin[elem_idx].gst = concat;
1169 gst_element_set_state(concat, GST_STATE_PAUSED);
1171 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1172 gst_bin_add(GST_BIN(pipeline), concat);
1179 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1181 GstElement *pipeline = NULL;
1182 GstElement *selector = NULL;
1183 GstPad *srcpad = NULL;
1186 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1188 selector = gst_element_factory_make("input-selector", NULL);
1190 LOGE("failed to create input-selector");
1193 g_object_set(selector, "sync-streams", TRUE, NULL);
1195 player->pipeline->mainbin[elem_idx].id = elem_idx;
1196 player->pipeline->mainbin[elem_idx].gst = selector;
1198 /* player->track[stream_type].active_track_index = DEFAULT_TRACK; */
1200 srcpad = gst_element_get_static_pad(selector, "src");
1202 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1203 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1204 __mmplayer_gst_selector_blocked, NULL, NULL);
1205 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1206 __mmplayer_gst_selector_event_probe, player, NULL);
1208 gst_element_set_state(selector, GST_STATE_PAUSED);
1210 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1211 gst_bin_add(GST_BIN(pipeline), selector);
1213 gst_object_unref(GST_OBJECT(srcpad));
1220 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1222 mmplayer_t *player = (mmplayer_t *)data;
1223 GstElement *combiner = NULL;
1224 GstCaps *caps = NULL;
1225 GstStructure *str = NULL;
1226 const gchar *name = NULL;
1227 GstPad *sinkpad = NULL;
1228 gboolean first_track = FALSE;
1229 gboolean caps_ret = TRUE;
1231 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1232 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1235 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1236 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1238 LOGD("pad-added signal handling");
1240 /* get mimetype from caps */
1241 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1245 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1247 LOGD("detected mimetype : %s", name);
1250 if (strstr(name, "video")) {
1252 gchar *caps_str = NULL;
1254 caps_str = gst_caps_to_string(caps);
1255 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1256 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1257 player->set_mode.video_zc = true;
1259 MMPLAYER_FREEIF(caps_str);
1261 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1262 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1264 LOGD("surface type : %d", stype);
1266 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1267 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1271 /* in case of exporting video frame, it requires the 360 video filter.
1272 * it will be handled in _no_more_pads(). */
1273 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1274 __mmplayer_gst_make_fakesink(player, pad, name);
1278 if (MMPLAYER_USE_DECODEBIN(player)) {
1279 LOGD("video selector is required");
1280 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1282 LOGD("video concat is required");
1283 elem_idx = MMPLAYER_M_V_CONCAT;
1285 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1286 } else if (strstr(name, "audio")) {
1287 gint samplerate = 0;
1290 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1291 if (player->build_audio_offload)
1292 player->no_more_pad = TRUE; /* remove state holder */
1293 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1297 gst_structure_get_int(str, "rate", &samplerate);
1298 gst_structure_get_int(str, "channels", &channels);
1300 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1301 __mmplayer_gst_make_fakesink(player, pad, name);
1304 if (MMPLAYER_USE_DECODEBIN(player)) {
1305 LOGD("audio selector is required");
1306 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1308 LOGD("audio concat is required");
1309 elem_idx = MMPLAYER_M_A_CONCAT;
1311 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1313 } else if (strstr(name, "text")) {
1314 if (MMPLAYER_USE_DECODEBIN(player)) {
1315 LOGD("text selector is required");
1316 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1318 LOGD("text concat is required");
1319 elem_idx = MMPLAYER_M_T_CONCAT;
1321 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1323 LOGE("invalid caps info");
1327 /* check selector and create it */
1328 if (!(combiner = player->pipeline->mainbin[elem_idx].gst)) {
1329 if (MMPLAYER_USE_DECODEBIN(player))
1330 combiner = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1332 combiner = __mmplayer_gst_make_concat(player, elem_idx);
1338 LOGD("Combiner element is already created.");
1342 sinkpad = gst_element_get_request_pad(combiner, "sink_%u");
1344 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1346 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1347 LOGE("failed to link combiner");
1348 gst_object_unref(GST_OBJECT(combiner));
1353 if (MMPLAYER_USE_DECODEBIN(player)) {
1354 LOGD("this track will be activated");
1355 g_object_set(combiner, "active-pad", sinkpad, NULL);
1359 if (MMPLAYER_USE_DECODEBIN(player))
1360 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1362 __mmplayer_create_sink_path(player, combiner, stream_type, caps);
1368 gst_caps_unref(caps);
1371 gst_object_unref(GST_OBJECT(sinkpad));
1379 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
1381 GstPad *srcpad = NULL;
1384 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1386 LOGD("type %d", type);
1389 LOGD("there is no %d track", type);
1393 srcpad = gst_element_get_static_pad(combiner, "src");
1395 LOGE("failed to get srcpad from combiner");
1399 LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
1401 __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
1403 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1404 if (player->track[type].block_id) {
1405 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1406 player->track[type].block_id = 0;
1410 gst_object_unref(GST_OBJECT(srcpad));
1419 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1421 gint active_index = 0;
1424 MMPLAYER_RETURN_IF_FAIL(player);
1426 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1428 /* change track to active pad */
1429 active_index = player->track[type].active_track_index;
1430 if ((active_index != DEFAULT_TRACK) &&
1431 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1432 LOGW("failed to change %d type track to %d", type, active_index);
1433 player->track[type].active_track_index = DEFAULT_TRACK;
1437 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1438 mm_player_set_attribute((MMHandleType)player, NULL,
1439 "content_text_track_num", player->track[type].total_track_num,
1440 "current_text_track_index", player->track[type].active_track_index, NULL);
1447 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1450 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1452 if (!audio_selector) {
1453 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1455 /* in case the source is changed, output can be changed. */
1456 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1457 LOGD("remove previous audiobin if it exist");
1459 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1460 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1462 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1463 MMPLAYER_FREEIF(player->pipeline->audiobin);
1466 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1467 _mmplayer_pipeline_complete(NULL, player);
1472 /* apply the audio track information */
1473 if (MMPLAYER_USE_DECODEBIN(player))
1474 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1476 /* create audio sink path */
1477 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
1478 LOGE("failed to create audio sink path");
1487 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1490 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1492 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1493 LOGD("text path is not supproted");
1497 /* apply the text track information */
1498 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1500 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1501 player->has_closed_caption = TRUE;
1503 /* create text decode path */
1504 player->no_more_pad = TRUE;
1506 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
1507 LOGE("failed to create text sink path");
1516 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1518 gint64 dur_bytes = 0L;
1521 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1522 player->pipeline->mainbin && player->streamer, FALSE);
1524 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1525 LOGE("fail to get duration.");
1527 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1528 * use file information was already set on Q2 when it was created. */
1529 _mm_player_streaming_set_queue2(player->streamer,
1530 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1531 TRUE, /* use_buffering */
1532 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1533 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1540 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1542 mmplayer_t *player = NULL;
1543 GstElement *video_selector = NULL;
1544 GstElement *audio_selector = NULL;
1545 GstElement *text_selector = NULL;
1548 player = (mmplayer_t *)data;
1550 LOGD("no-more-pad signal handling");
1552 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1553 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1554 LOGW("player is shutting down");
1558 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1559 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1560 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1561 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1562 LOGE("failed to set queue2 buffering");
1567 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1568 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1569 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1571 if (!video_selector && !audio_selector && !text_selector) {
1572 LOGW("there is no selector");
1573 player->no_more_pad = TRUE;
1577 /* create video path followed by video-select */
1578 if (video_selector && !audio_selector && !text_selector)
1579 player->no_more_pad = TRUE;
1581 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
1584 /* create audio path followed by audio-select */
1585 if (audio_selector && !text_selector)
1586 player->no_more_pad = TRUE;
1588 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1591 /* create text path followed by text-select */
1592 __mmplayer_create_text_sink_path(player, text_selector);
1595 _mmplayer_set_reconfigure_state(player, FALSE);
1600 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1602 gboolean ret = FALSE;
1603 GstElement *pipeline = NULL;
1604 GstPad *sinkpad = NULL;
1607 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1608 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1610 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1612 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1614 LOGE("failed to get pad from sinkbin");
1620 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1621 LOGE("failed to link sinkbin for reusing");
1622 goto EXIT; /* exit either pass or fail */
1626 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1627 LOGE("failed to set state(READY) to sinkbin");
1632 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1633 LOGE("failed to add sinkbin to pipeline");
1638 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1639 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1644 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1645 LOGE("failed to set state(PAUSED) to sinkbin");
1654 gst_object_unref(GST_OBJECT(sinkpad));
1662 __mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
1664 mmplayer_t *player = NULL;
1665 GstCaps *caps = NULL;
1666 gchar *caps_str = NULL;
1667 GstStructure *str = NULL;
1668 const gchar *name = NULL;
1669 GstElement *sinkbin = NULL;
1670 gboolean reusing = FALSE;
1671 gboolean caps_ret = TRUE;
1672 gchar *sink_pad_name = "sink";
1675 player = (mmplayer_t *)data;
1678 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1679 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1680 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1682 MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
1686 caps = gst_caps_ref(ref_caps);
1689 caps_str = gst_caps_to_string(caps);
1691 LOGD("detected mimetype : %s", name);
1693 if (strstr(name, "audio")) {
1694 if (player->pipeline->audiobin == NULL) {
1695 const gchar *audio_format = gst_structure_get_string(str, "format");
1697 LOGD("original audio format %s", audio_format);
1698 mm_player_set_attribute((MMHandleType)player, NULL,
1699 "content_audio_format", audio_format, strlen(audio_format), NULL);
1702 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1703 LOGE("failed to create audiobin. continuing without audio");
1707 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1708 LOGD("creating audiobin success");
1711 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1712 LOGD("reusing audiobin");
1713 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1715 } else if (strstr(name, "video")) {
1716 /* 1. zero copy is updated at _decode_pad_added()
1717 * 2. NULL surface type is handled in _decode_pad_added() */
1718 LOGD("zero copy %d", player->set_mode.video_zc);
1719 if (player->pipeline->videobin == NULL) {
1720 int surface_type = 0;
1721 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1722 LOGD("display_surface_type (%d)", surface_type);
1724 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1725 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1726 LOGE("failed to acquire video overlay resource");
1730 player->interrupted_by_resource = FALSE;
1732 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1733 LOGE("failed to create videobin. continuing without video");
1737 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1738 LOGD("creating videosink bin success");
1741 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1742 LOGD("re-using videobin");
1743 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1745 } else if (strstr(name, "text")) {
1746 if (player->pipeline->textbin == NULL) {
1747 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1748 LOGE("failed to create text sink bin. continuing without text");
1752 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1753 player->textsink_linked = 1;
1754 LOGD("creating textsink bin success");
1756 if (!player->textsink_linked) {
1757 LOGD("re-using textbin");
1759 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1760 player->textsink_linked = 1;
1762 /* linked textbin exist which means that the external subtitle path exist already */
1763 LOGW("ignoring internal subtutle since external subtitle is available");
1766 sink_pad_name = "text_sink";
1768 LOGW("unknown mime type %s, ignoring it", name);
1772 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1775 LOGD("[handle: %p] success to create and link sink bin", 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)", 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);
1801 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1803 int required_angle = 0; /* Angle required for straight view */
1804 int rotation_angle = 0;
1806 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1807 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1809 /* Counter clockwise */
1810 switch (orientation) {
1815 required_angle = 270;
1818 required_angle = 180;
1821 required_angle = 90;
1825 rotation_angle = display_angle + required_angle;
1826 if (rotation_angle >= 360)
1827 rotation_angle -= 360;
1829 /* chech if supported or not */
1830 if (rotation_angle % 90) {
1831 LOGD("not supported rotation angle = %d", rotation_angle);
1835 switch (rotation_angle) {
1837 *value = MM_DISPLAY_ROTATION_NONE;
1840 *value = MM_DISPLAY_ROTATION_90;
1843 *value = MM_DISPLAY_ROTATION_180;
1846 *value = MM_DISPLAY_ROTATION_270;
1850 LOGD("setting rotation property value : %d", *value);
1856 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1858 int display_rotation = 0;
1859 gchar *org_orient = NULL;
1860 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1863 LOGE("cannot get content attribute");
1864 return MM_ERROR_PLAYER_INTERNAL;
1867 if (display_angle) {
1868 /* update user roation */
1869 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1871 /* Counter clockwise */
1872 switch (display_rotation) {
1873 case MM_DISPLAY_ROTATION_NONE:
1876 case MM_DISPLAY_ROTATION_90:
1877 *display_angle = 90;
1879 case MM_DISPLAY_ROTATION_180:
1880 *display_angle = 180;
1882 case MM_DISPLAY_ROTATION_270:
1883 *display_angle = 270;
1886 LOGW("wrong angle type : %d", display_rotation);
1889 LOGD("check user angle: %d", *display_angle);
1893 /* Counter clockwise */
1894 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1897 if (!strcmp(org_orient, "rotate-90"))
1899 else if (!strcmp(org_orient, "rotate-180"))
1901 else if (!strcmp(org_orient, "rotate-270"))
1904 LOGD("original rotation is %s", org_orient);
1906 LOGD("content_video_orientation get fail");
1909 LOGD("check orientation: %d", *orientation);
1912 return MM_ERROR_NONE;
1915 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1917 int rotation_value = 0;
1918 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1919 int display_angle = 0;
1922 /* check video sinkbin is created */
1923 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1926 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1928 /* get rotation value to set */
1929 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1930 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1931 LOGD("set video param : rotate %d", rotation_value);
1934 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1936 MMHandleType attrs = 0;
1940 /* check video sinkbin is created */
1941 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1944 attrs = MMPLAYER_GET_ATTRS(player);
1945 MMPLAYER_RETURN_IF_FAIL(attrs);
1947 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1948 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1949 LOGD("set video param : visible %d", visible);
1952 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1954 MMHandleType attrs = 0;
1955 int display_method = 0;
1958 /* check video sinkbin is created */
1959 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1962 attrs = MMPLAYER_GET_ATTRS(player);
1963 MMPLAYER_RETURN_IF_FAIL(attrs);
1965 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1966 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1967 LOGD("set video param : method %d", display_method);
1970 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1972 MMHandleType attrs = 0;
1976 /* check video sinkbin is created */
1977 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1980 attrs = MMPLAYER_GET_ATTRS(player);
1981 MMPLAYER_RETURN_IF_FAIL(attrs);
1983 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1984 MMPLAYER_RETURN_IF_FAIL(handle);
1986 gst_video_overlay_set_video_roi_area(
1987 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1988 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1989 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1990 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1993 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1995 MMHandleType attrs = 0;
2000 int win_roi_width = 0;
2001 int win_roi_height = 0;
2004 /* check video sinkbin is created */
2005 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2008 attrs = MMPLAYER_GET_ATTRS(player);
2009 MMPLAYER_RETURN_IF_FAIL(attrs);
2011 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2012 MMPLAYER_RETURN_IF_FAIL(handle);
2014 /* It should be set after setting window */
2015 mm_attrs_multiple_get(attrs, NULL,
2016 "display_win_roi_x", &win_roi_x,
2017 "display_win_roi_y", &win_roi_y,
2018 "display_win_roi_width", &win_roi_width,
2019 "display_win_roi_height", &win_roi_height, NULL);
2021 /* After setting window handle, set display roi area */
2022 gst_video_overlay_set_display_roi_area(
2023 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2024 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2025 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2026 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2029 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2031 MMHandleType attrs = 0;
2034 /* check video sinkbin is created */
2035 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2038 attrs = MMPLAYER_GET_ATTRS(player);
2039 MMPLAYER_RETURN_IF_FAIL(attrs);
2041 /* common case if using overlay surface */
2042 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2043 MMPLAYER_RETURN_IF_FAIL(handle);
2045 /* default is using wl_surface_id */
2046 LOGD("set video param : wl_surface_id %d", handle);
2047 gst_video_overlay_set_wl_window_wl_surface_id(
2048 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2053 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2055 gboolean update_all_param = FALSE;
2059 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
2060 LOGW("videosink is not ready yet");
2061 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2064 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2065 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2066 return MM_ERROR_PLAYER_INTERNAL;
2069 LOGD("param_name : %s", param_name);
2070 if (!g_strcmp0(param_name, "update_all_param"))
2071 update_all_param = TRUE;
2073 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2074 __mmplayer_video_param_set_display_overlay(player);
2075 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2076 __mmplayer_video_param_set_display_method(player);
2077 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2078 __mmplayer_video_param_set_display_visible(player);
2079 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2080 __mmplayer_video_param_set_display_rotation(player);
2081 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2082 __mmplayer_video_param_set_roi_area(player);
2083 if (update_all_param)
2084 __mmplayer_video_param_set_video_roi_area(player);
2088 return MM_ERROR_NONE;
2092 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2094 gboolean disable_overlay = FALSE;
2095 mmplayer_t *player = (mmplayer_t *)hplayer;
2098 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2099 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2100 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2101 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2103 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2104 LOGW("Display control is not supported");
2105 return MM_ERROR_PLAYER_INTERNAL;
2108 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2110 if (audio_only == (bool)disable_overlay) {
2111 LOGE("It's the same with current setting: (%d)", audio_only);
2112 return MM_ERROR_NONE;
2116 LOGE("disable overlay");
2117 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2119 /* release overlay resource */
2120 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2121 LOGE("failed to release overlay resource");
2125 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2126 LOGE("failed to acquire video overlay resource");
2129 player->interrupted_by_resource = FALSE;
2131 LOGD("enable overlay");
2132 __mmplayer_video_param_set_display_overlay(player);
2133 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2138 return MM_ERROR_NONE;
2142 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2144 mmplayer_t *player = (mmplayer_t *)hplayer;
2145 gboolean disable_overlay = FALSE;
2149 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2150 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2151 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2152 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2153 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2155 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2156 LOGW("Display control is not supported");
2157 return MM_ERROR_PLAYER_INTERNAL;
2160 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2162 *paudio_only = (bool)disable_overlay;
2164 LOGD("audio_only : %d", *paudio_only);
2168 return MM_ERROR_NONE;
2172 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2174 GList *bucket = element_bucket;
2175 mmplayer_gst_element_t *element = NULL;
2176 mmplayer_gst_element_t *prv_element = NULL;
2177 GstElement *tee_element = NULL;
2178 gint successful_link_count = 0;
2182 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2184 prv_element = (mmplayer_gst_element_t *)bucket->data;
2185 bucket = bucket->next;
2187 for (; bucket; bucket = bucket->next) {
2188 element = (mmplayer_gst_element_t *)bucket->data;
2190 if (element && element->gst) {
2191 if (prv_element && prv_element->gst) {
2192 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2194 prv_element->gst = tee_element;
2196 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2197 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2198 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2202 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2203 LOGD("linking [%s] to [%s] success",
2204 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2205 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2206 successful_link_count++;
2207 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2208 LOGD("keep audio-tee element for next audio pipeline branch");
2209 tee_element = prv_element->gst;
2212 LOGD("linking [%s] to [%s] failed",
2213 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2214 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2220 prv_element = element;
2225 return successful_link_count;
2229 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2231 GList *bucket = element_bucket;
2232 mmplayer_gst_element_t *element = NULL;
2233 int successful_add_count = 0;
2237 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2238 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2240 for (; bucket; bucket = bucket->next) {
2241 element = (mmplayer_gst_element_t *)bucket->data;
2243 if (element && element->gst) {
2244 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2245 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2246 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2247 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2250 successful_add_count++;
2256 return successful_add_count;
2260 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2262 mmplayer_t *player = (mmplayer_t *)data;
2263 GstCaps *caps = NULL;
2264 GstStructure *str = NULL;
2266 gboolean caps_ret = TRUE;
2270 MMPLAYER_RETURN_IF_FAIL(pad);
2271 MMPLAYER_RETURN_IF_FAIL(unused);
2272 MMPLAYER_RETURN_IF_FAIL(data);
2274 caps = gst_pad_get_current_caps(pad);
2278 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2282 LOGD("name = %s", name);
2284 if (strstr(name, "audio")) {
2285 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2287 if (player->audio_stream_changed_cb) {
2288 LOGE("call the audio stream changed cb");
2289 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2291 } else if (strstr(name, "video")) {
2292 if ((name = gst_structure_get_string(str, "format")))
2293 player->set_mode.video_zc = name[0] == 'S';
2295 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2296 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2298 LOGW("invalid caps info");
2303 gst_caps_unref(caps);
2311 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2316 MMPLAYER_RETURN_IF_FAIL(player);
2318 if (player->audio_stream_buff_list) {
2319 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2320 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2323 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2324 __mmplayer_audio_stream_send_data(player, tmp);
2326 MMPLAYER_FREEIF(tmp->pcm_data);
2327 MMPLAYER_FREEIF(tmp);
2330 g_list_free(player->audio_stream_buff_list);
2331 player->audio_stream_buff_list = NULL;
2338 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2340 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2343 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2345 audio_stream.bitrate = a_buffer->bitrate;
2346 audio_stream.channel = a_buffer->channel;
2347 audio_stream.channel_mask = a_buffer->channel_mask;
2348 audio_stream.data_size = a_buffer->data_size;
2349 audio_stream.data = a_buffer->pcm_data;
2350 audio_stream.pcm_format = a_buffer->pcm_format;
2352 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2354 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2360 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2362 mmplayer_t *player = (mmplayer_t *)data;
2363 const gchar *pcm_format = NULL;
2366 guint64 channel_mask = 0;
2367 void *a_data = NULL;
2369 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2370 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2374 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2376 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2377 a_data = mapinfo.data;
2378 a_size = mapinfo.size;
2380 GstCaps *caps = gst_pad_get_current_caps(pad);
2381 GstStructure *structure = gst_caps_get_structure(caps, 0);
2383 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2385 pcm_format = gst_structure_get_string(structure, "format");
2386 gst_structure_get_int(structure, "rate", &rate);
2387 gst_structure_get_int(structure, "channels", &channel);
2388 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2389 gst_caps_unref(GST_CAPS(caps));
2391 /* In case of the sync is false, use buffer list. *
2392 * The num of buffer list depends on the num of audio channels */
2393 if (player->audio_stream_buff_list) {
2394 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2395 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2397 if (channel_mask == tmp->channel_mask) {
2399 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2401 if (tmp->data_size + a_size < tmp->buff_size) {
2402 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2403 tmp->data_size += a_size;
2405 /* send data to client */
2406 __mmplayer_audio_stream_send_data(player, tmp);
2408 if (a_size > tmp->buff_size) {
2409 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2410 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2411 if (tmp->pcm_data == NULL) {
2412 LOGE("failed to realloc data.");
2415 tmp->buff_size = a_size;
2417 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2418 memcpy(tmp->pcm_data, a_data, a_size);
2419 tmp->data_size = a_size;
2424 LOGE("data is empty in list.");
2430 /* create new audio stream data for newly found audio channel */
2431 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2432 if (a_buffer == NULL) {
2433 LOGE("failed to alloc data.");
2436 a_buffer->bitrate = rate;
2437 a_buffer->channel = channel;
2438 a_buffer->channel_mask = channel_mask;
2439 a_buffer->data_size = a_size;
2440 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2442 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2443 /* If sync is FALSE, use buffer list to reduce the IPC. */
2444 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2445 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2446 if (a_buffer->pcm_data == NULL) {
2447 LOGE("failed to alloc data.");
2448 MMPLAYER_FREEIF(a_buffer);
2451 memcpy(a_buffer->pcm_data, a_data, a_size);
2453 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2455 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2457 /* If sync is TRUE, send data directly. */
2458 a_buffer->pcm_data = a_data;
2459 __mmplayer_audio_stream_send_data(player, a_buffer);
2460 MMPLAYER_FREEIF(a_buffer);
2464 gst_buffer_unmap(buffer, &mapinfo);
2469 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2471 mmplayer_t *player = (mmplayer_t *)data;
2472 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2473 GstPad *sinkpad = NULL;
2474 GstElement *queue = NULL, *sink = NULL;
2477 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2479 queue = gst_element_factory_make("queue", NULL);
2480 if (queue == NULL) {
2481 LOGD("fail make queue");
2485 sink = gst_element_factory_make("fakesink", NULL);
2487 LOGD("fail make fakesink");
2491 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2493 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2494 LOGW("failed to link queue & sink");
2498 sinkpad = gst_element_get_static_pad(queue, "sink");
2500 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2501 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2505 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2507 gst_object_unref(sinkpad);
2508 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2509 g_object_set(sink, "sync", TRUE, NULL);
2510 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2512 /* keep the first sink reference only */
2513 if (!audiobin[MMPLAYER_A_SINK].gst) {
2514 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2515 audiobin[MMPLAYER_A_SINK].gst = sink;
2519 _mmplayer_add_signal_connection(player,
2521 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2523 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2526 __mmplayer_add_sink(player, sink);
2528 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2529 LOGE("failed to sync state");
2533 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2534 LOGE("failed to sync state");
2542 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2544 gst_object_unref(GST_OBJECT(queue));
2548 gst_object_unref(GST_OBJECT(sink));
2552 gst_object_unref(GST_OBJECT(sinkpad));
2560 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2562 mmplayer_t *player = (mmplayer_t *)data;
2565 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2567 player->no_more_pad = TRUE;
2568 _mmplayer_pipeline_complete(NULL, player);
2575 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2577 #define MAX_PROPS_LEN 128
2578 mmplayer_gst_element_t *audiobin = NULL;
2579 gint latency_mode = 0;
2580 gchar *stream_type = NULL;
2581 gchar *latency = NULL;
2583 gchar stream_props[MAX_PROPS_LEN] = {0,};
2584 GstStructure *props = NULL;
2587 * It should be set after player creation through attribute.
2588 * But, it can not be changed during playing.
2591 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2593 audiobin = player->pipeline->audiobin;
2595 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2596 if (player->sound.mute) {
2597 LOGD("mute enabled");
2598 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2601 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2602 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2605 snprintf(stream_props, sizeof(stream_props) - 1,
2606 "props,application.process.id.origin=%d", player->client_pid);
2608 snprintf(stream_props, sizeof(stream_props) - 1,
2609 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2610 stream_type, stream_id, player->client_pid);
2612 props = gst_structure_from_string(stream_props, NULL);
2613 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2614 LOGI("props result[%s].", stream_props);
2615 gst_structure_free(props);
2617 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2619 switch (latency_mode) {
2620 case AUDIO_LATENCY_MODE_LOW:
2621 latency = g_strdup("low");
2623 case AUDIO_LATENCY_MODE_MID:
2624 latency = g_strdup("mid");
2626 case AUDIO_LATENCY_MODE_HIGH:
2627 latency = g_strdup("high");
2630 latency = g_strdup("mid");
2634 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2636 LOGD("audiosink property - latency=%s", latency);
2638 MMPLAYER_FREEIF(latency);
2644 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2646 mmplayer_gst_element_t *audiobin = NULL;
2649 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2650 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2652 audiobin = player->pipeline->audiobin;
2654 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2655 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2656 LOGE("failed to create media stream info");
2657 return MM_ERROR_PLAYER_INTERNAL;
2660 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2662 if (player->video360_yaw_radians <= M_PI &&
2663 player->video360_yaw_radians >= -M_PI &&
2664 player->video360_pitch_radians <= M_PI_2 &&
2665 player->video360_pitch_radians >= -M_PI_2) {
2666 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2667 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2668 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2669 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2670 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2671 "source-orientation-y", player->video360_metadata.init_view_heading,
2672 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2676 return MM_ERROR_NONE;
2680 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2682 mmplayer_gst_element_t *audiobin = NULL;
2683 GstPad *sink_pad = NULL;
2684 GstCaps *acaps = NULL;
2686 int pitch_control = 0;
2687 double pitch_value = 1.0;
2690 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2691 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2693 audiobin = player->pipeline->audiobin;
2695 LOGD("make element for normal audio playback");
2697 /* audio bin structure for playback. {} means optional.
2698 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2700 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2701 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2704 /* for pitch control */
2705 mm_attrs_multiple_get(player->attrs, NULL,
2706 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2707 MM_PLAYER_PITCH_VALUE, &pitch_value,
2710 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2711 if (pitch_control && (player->videodec_linked == 0)) {
2712 GstElementFactory *factory;
2714 factory = gst_element_factory_find("pitch");
2716 gst_object_unref(factory);
2719 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2722 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2723 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2725 LOGW("there is no pitch element");
2730 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2732 /* replaygain volume */
2733 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2734 if (player->sound.rg_enable)
2735 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2737 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2740 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2742 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2743 /* currently, only openalsink uses volume element */
2744 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2745 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2747 if (player->sound.mute) {
2748 LOGD("mute enabled");
2749 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2753 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2755 /* audio effect element. if audio effect is enabled */
2756 if ((strcmp(player->ini.audioeffect_element, ""))
2758 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2759 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2761 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2763 if ((!player->bypass_audio_effect)
2764 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2765 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2766 if (!_mmplayer_audio_effect_custom_apply(player))
2767 LOGI("apply audio effect(custom) setting success");
2771 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2772 && (player->set_mode.rich_audio)) {
2773 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2777 /* create audio sink */
2778 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2779 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2780 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2782 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2783 if (player->is_360_feature_enabled &&
2784 player->is_content_spherical &&
2786 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2787 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2788 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2790 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2792 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2794 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2795 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2796 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2797 gst_caps_unref(acaps);
2799 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2801 player->is_openal_plugin_used = TRUE;
2803 if (player->is_360_feature_enabled && player->is_content_spherical)
2804 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2805 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2808 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2809 (player->videodec_linked && player->ini.use_system_clock)) {
2810 LOGD("system clock will be used.");
2811 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2814 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2815 __mmplayer_gst_set_pulsesink_property(player);
2816 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2817 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2822 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2823 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2825 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2826 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2827 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2828 gst_object_unref(GST_OBJECT(sink_pad));
2830 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2833 return MM_ERROR_NONE;
2835 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2837 return MM_ERROR_PLAYER_INTERNAL;
2841 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2843 mmplayer_gst_element_t *audiobin = NULL;
2844 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2846 gchar *dst_format = NULL;
2848 int dst_samplerate = 0;
2849 int dst_channels = 0;
2850 GstCaps *caps = NULL;
2851 char *caps_str = NULL;
2854 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2855 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2857 audiobin = player->pipeline->audiobin;
2859 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2861 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2863 [case 1] extract interleave audio pcm without playback
2864 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2865 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2867 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2869 [case 2] deinterleave for each channel without playback
2870 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2871 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2873 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2874 - fakesink (sync or not)
2877 [case 3] [case 1(sync only)] + playback
2878 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2880 * src - ... - tee - queue1 - playback path
2881 - queue2 - [case1 pipeline with sync]
2883 [case 4] [case 2(sync only)] + playback
2884 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2886 * src - ... - tee - queue1 - playback path
2887 - queue2 - [case2 pipeline with sync]
2891 /* 1. create tee and playback path
2892 'tee' should be added at first to copy the decoded stream
2894 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2895 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2896 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2898 /* tee - path 1 : for playback path */
2899 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2900 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2902 /* tee - path 2 : for extract path */
2903 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2904 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2907 /* if there is tee, 'tee - path 2' is linked here */
2909 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2912 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2914 /* 2. decide the extract pcm format */
2915 mm_attrs_multiple_get(player->attrs, NULL,
2916 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2917 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2918 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2921 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2922 dst_format, dst_len, dst_samplerate, dst_channels);
2924 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2925 mm_attrs_multiple_get(player->attrs, NULL,
2926 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2927 "content_audio_samplerate", &dst_samplerate,
2928 "content_audio_channels", &dst_channels,
2931 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2932 dst_format, dst_len, dst_samplerate, dst_channels);
2934 /* If there is no enough information, set it to platform default value. */
2935 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2936 LOGD("set platform default format");
2937 dst_format = DEFAULT_PCM_OUT_FORMAT;
2939 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2940 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2943 /* 3. create capsfilter */
2944 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2945 caps = gst_caps_new_simple("audio/x-raw",
2946 "format", G_TYPE_STRING, dst_format,
2947 "rate", G_TYPE_INT, dst_samplerate,
2948 "channels", G_TYPE_INT, dst_channels,
2951 caps_str = gst_caps_to_string(caps);
2952 LOGD("new caps : %s", caps_str);
2954 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2957 gst_caps_unref(caps);
2958 MMPLAYER_FREEIF(caps_str);
2960 /* 4-1. create deinterleave to extract pcm for each channel */
2961 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2962 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2963 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2965 /* audiosink will be added after getting signal for each channel */
2966 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2967 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2968 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2969 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2970 player->no_more_pad = FALSE;
2972 /* 4-2. create fakesink to extract interlevaed pcm */
2973 LOGD("add audio fakesink for interleaved audio");
2974 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2975 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2976 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2977 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2979 _mmplayer_add_signal_connection(player,
2980 G_OBJECT(audiobin[extract_sink_id].gst),
2981 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2983 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2986 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2990 return MM_ERROR_NONE;
2992 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2994 return MM_ERROR_PLAYER_INTERNAL;
2998 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3000 int ret = MM_ERROR_NONE;
3001 mmplayer_gst_element_t *audiobin = NULL;
3002 GList *element_bucket = NULL;
3005 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3006 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3008 audiobin = player->pipeline->audiobin;
3010 if (player->build_audio_offload) { /* skip all the audio filters */
3011 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3013 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3014 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3015 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3017 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
3021 /* FIXME: need to mention the supportable condition at API reference */
3022 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3023 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3025 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3027 if (ret != MM_ERROR_NONE)
3030 LOGD("success to make audio bin element");
3031 *bucket = element_bucket;
3034 return MM_ERROR_NONE;
3037 LOGE("failed to make audio bin element");
3038 g_list_free(element_bucket);
3042 return MM_ERROR_PLAYER_INTERNAL;
3046 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3048 mmplayer_gst_element_t *first_element = NULL;
3049 mmplayer_gst_element_t *audiobin = NULL;
3051 GstPad *ghostpad = NULL;
3052 GList *element_bucket = NULL;
3056 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3059 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3061 LOGE("failed to allocate memory for audiobin");
3062 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3066 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3067 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3068 if (!audiobin[MMPLAYER_A_BIN].gst) {
3069 LOGE("failed to create audiobin");
3074 player->pipeline->audiobin = audiobin;
3076 /* create audio filters and audiosink */
3077 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3080 /* adding created elements to bin */
3081 LOGD("adding created elements to bin");
3082 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3085 /* linking elements in the bucket by added order. */
3086 LOGD("Linking elements in the bucket by added order.");
3087 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3090 /* get first element's sinkpad for creating ghostpad */
3091 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3092 if (!first_element) {
3093 LOGE("failed to get first elem");
3097 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3099 LOGE("failed to get pad from first element of audiobin");
3103 ghostpad = gst_ghost_pad_new("sink", pad);
3105 LOGE("failed to create ghostpad");
3109 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3110 LOGE("failed to add ghostpad to audiobin");
3114 gst_object_unref(pad);
3116 g_list_free(element_bucket);
3119 return MM_ERROR_NONE;
3122 LOGD("ERROR : releasing audiobin");
3125 gst_object_unref(GST_OBJECT(pad));
3128 gst_object_unref(GST_OBJECT(ghostpad));
3131 g_list_free(element_bucket);
3133 /* release element which are not added to bin */
3134 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3135 /* NOTE : skip bin */
3136 if (audiobin[i].gst) {
3137 GstObject *parent = NULL;
3138 parent = gst_element_get_parent(audiobin[i].gst);
3141 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3142 audiobin[i].gst = NULL;
3144 gst_object_unref(GST_OBJECT(parent));
3148 /* release audiobin with it's childs */
3149 if (audiobin[MMPLAYER_A_BIN].gst)
3150 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3152 MMPLAYER_FREEIF(audiobin);
3154 player->pipeline->audiobin = NULL;
3156 return MM_ERROR_PLAYER_INTERNAL;
3160 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3162 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3166 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3168 int ret = MM_ERROR_NONE;
3170 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3171 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3173 MMPLAYER_VIDEO_BO_LOCK(player);
3175 if (player->video_bo_list) {
3176 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3177 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3178 if (tmp && tmp->bo == bo) {
3180 LOGD("release bo %p", bo);
3181 tbm_bo_unref(tmp->bo);
3182 MMPLAYER_VIDEO_BO_UNLOCK(player);
3183 MMPLAYER_VIDEO_BO_SIGNAL(player);
3188 /* hw codec is running or the list was reset for DRC. */
3189 LOGW("there is no bo list.");
3191 MMPLAYER_VIDEO_BO_UNLOCK(player);
3193 LOGW("failed to find bo %p", bo);
3197 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3203 tbm_bo_unref(tmp->bo);
3208 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3211 MMPLAYER_RETURN_IF_FAIL(player);
3213 MMPLAYER_VIDEO_BO_LOCK(player);
3214 if (player->video_bo_list) {
3215 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3216 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3217 player->video_bo_list = NULL;
3219 player->video_bo_size = 0;
3220 MMPLAYER_VIDEO_BO_UNLOCK(player);
3227 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3230 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3231 gboolean ret = TRUE;
3233 /* check DRC, if it is, destroy the prev bo list to create again */
3234 if (player->video_bo_size != size) {
3235 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3236 __mmplayer_video_stream_destroy_bo_list(player);
3237 player->video_bo_size = size;
3240 MMPLAYER_VIDEO_BO_LOCK(player);
3242 if ((!player->video_bo_list) ||
3243 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3245 /* create bo list */
3247 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3249 if (player->video_bo_list) {
3250 /* if bo list did not created all, try it again. */
3251 idx = g_list_length(player->video_bo_list);
3252 LOGD("bo list exist(len: %d)", idx);
3255 for (; idx < player->ini.num_of_video_bo; idx++) {
3256 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3258 LOGE("Fail to alloc bo_info.");
3261 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3263 LOGE("Fail to tbm_bo_alloc.");
3264 MMPLAYER_FREEIF(bo_info);
3267 bo_info->used = FALSE;
3268 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3271 /* update video num buffers */
3272 LOGD("video_num_buffers : %d", idx);
3273 mm_player_set_attribute((MMHandleType)player, NULL,
3274 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3275 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3279 MMPLAYER_VIDEO_BO_UNLOCK(player);
3285 /* get bo from list*/
3286 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3287 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3288 if (tmp && (tmp->used == FALSE)) {
3289 LOGD("found bo %p to use", tmp->bo);
3291 MMPLAYER_VIDEO_BO_UNLOCK(player);
3292 return tbm_bo_ref(tmp->bo);
3296 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3297 MMPLAYER_VIDEO_BO_UNLOCK(player);
3301 if (player->ini.video_bo_timeout <= 0) {
3302 MMPLAYER_VIDEO_BO_WAIT(player);
3304 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3305 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3312 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3314 mmplayer_t *player = (mmplayer_t *)data;
3316 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3318 /* send prerolled pkt */
3319 player->video_stream_prerolled = false;
3321 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3323 /* not to send prerolled pkt again */
3324 player->video_stream_prerolled = true;
3328 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3330 mmplayer_t *player = (mmplayer_t *)data;
3331 mmplayer_video_decoded_data_info_t *stream = NULL;
3332 GstMemory *mem = NULL;
3335 MMPLAYER_RETURN_IF_FAIL(player);
3336 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3338 if (player->video_stream_prerolled) {
3339 player->video_stream_prerolled = false;
3340 LOGD("skip the prerolled pkt not to send it again");
3344 /* clear stream data structure */
3345 stream = __mmplayer_create_stream_from_pad(pad);
3347 LOGE("failed to alloc stream");
3351 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3353 /* set size and timestamp */
3354 mem = gst_buffer_peek_memory(buffer, 0);
3355 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3356 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3358 /* check zero-copy */
3359 if (player->set_mode.video_zc &&
3360 player->set_mode.video_export &&
3361 gst_is_tizen_memory(mem)) {
3362 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3363 stream->internal_buffer = gst_buffer_ref(buffer);
3364 } else { /* sw codec */
3365 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3368 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3372 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3373 LOGE("failed to send video decoded data.");
3380 LOGE("release video stream resource.");
3381 if (gst_is_tizen_memory(mem)) {
3383 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3385 tbm_bo_unref(stream->bo[i]);
3388 /* unref gst buffer */
3389 if (stream->internal_buffer)
3390 gst_buffer_unref(stream->internal_buffer);
3393 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3395 MMPLAYER_FREEIF(stream);
3400 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3402 mmplayer_gst_element_t *videobin = NULL;
3405 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3407 videobin = player->pipeline->videobin;
3409 /* Set spatial media metadata and/or user settings to the element.
3411 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3412 "projection-type", player->video360_metadata.projection_type, NULL);
3414 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3415 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3417 if (player->video360_metadata.full_pano_width_pixels &&
3418 player->video360_metadata.full_pano_height_pixels &&
3419 player->video360_metadata.cropped_area_image_width &&
3420 player->video360_metadata.cropped_area_image_height) {
3421 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3422 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3423 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3424 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3425 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3426 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3427 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3431 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3432 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3433 "horizontal-fov", player->video360_horizontal_fov,
3434 "vertical-fov", player->video360_vertical_fov, NULL);
3437 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3438 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3439 "zoom", 1.0f / player->video360_zoom, NULL);
3442 if (player->video360_yaw_radians <= M_PI &&
3443 player->video360_yaw_radians >= -M_PI &&
3444 player->video360_pitch_radians <= M_PI_2 &&
3445 player->video360_pitch_radians >= -M_PI_2) {
3446 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3447 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3448 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3449 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3450 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3451 "pose-yaw", player->video360_metadata.init_view_heading,
3452 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3455 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3456 "passthrough", !player->is_video360_enabled, NULL);
3463 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3465 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3466 GList *element_bucket = NULL;
3469 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3471 /* create video360 filter */
3472 if (player->is_360_feature_enabled && player->is_content_spherical) {
3473 LOGD("create video360 element");
3474 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3475 __mmplayer_gst_set_video360_property(player);
3479 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3480 LOGD("skip creating the videoconv and rotator");
3481 return MM_ERROR_NONE;
3484 /* in case of sw codec & overlay surface type, except 360 playback.
3485 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3486 LOGD("create video converter: %s", video_csc);
3487 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3490 *bucket = element_bucket;
3492 return MM_ERROR_NONE;
3494 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3495 g_list_free(element_bucket);
3499 return MM_ERROR_PLAYER_INTERNAL;
3503 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3505 gchar *factory_name = NULL;
3507 switch (surface_type) {
3508 case MM_DISPLAY_SURFACE_OVERLAY:
3509 if (strlen(player->ini.videosink_element_overlay) > 0)
3510 factory_name = player->ini.videosink_element_overlay;
3512 case MM_DISPLAY_SURFACE_REMOTE:
3513 case MM_DISPLAY_SURFACE_NULL:
3514 if (strlen(player->ini.videosink_element_fake) > 0)
3515 factory_name = player->ini.videosink_element_fake;
3518 LOGE("unidentified surface type");
3522 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3523 return factory_name;
3527 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3529 gchar *factory_name = NULL;
3530 mmplayer_gst_element_t *videobin = NULL;
3535 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3537 videobin = player->pipeline->videobin;
3538 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3540 attrs = MMPLAYER_GET_ATTRS(player);
3542 LOGE("cannot get content attribute");
3543 return MM_ERROR_PLAYER_INTERNAL;
3546 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3547 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3548 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3549 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3550 "use-tbm", use_tbm, NULL);
3553 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3554 return MM_ERROR_PLAYER_INTERNAL;
3556 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3559 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3560 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3563 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3565 LOGD("disable last-sample");
3566 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3569 if (player->set_mode.video_export) {
3571 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3572 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3573 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3575 _mmplayer_add_signal_connection(player,
3576 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3577 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3579 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3582 _mmplayer_add_signal_connection(player,
3583 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3584 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3586 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3590 if (videobin[MMPLAYER_V_SINK].gst) {
3591 GstPad *sink_pad = NULL;
3592 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3594 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3595 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3596 gst_object_unref(GST_OBJECT(sink_pad));
3598 LOGE("failed to get sink pad from videosink");
3602 return MM_ERROR_NONE;
3607 * - video overlay surface(arm/x86) : tizenwlsink
3610 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3613 GList *element_bucket = NULL;
3614 mmplayer_gst_element_t *first_element = NULL;
3615 mmplayer_gst_element_t *videobin = NULL;
3616 gchar *videosink_factory_name = NULL;
3619 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3622 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3624 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3626 player->pipeline->videobin = videobin;
3629 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3630 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3631 if (!videobin[MMPLAYER_V_BIN].gst) {
3632 LOGE("failed to create videobin");
3636 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3639 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3640 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3642 /* additional setting for sink plug-in */
3643 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3644 LOGE("failed to set video property");
3648 /* store it as it's sink element */
3649 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3651 /* adding created elements to bin */
3652 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3653 LOGE("failed to add elements");
3657 /* Linking elements in the bucket by added order */
3658 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3659 LOGE("failed to link elements");
3663 /* get first element's sinkpad for creating ghostpad */
3664 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3665 if (!first_element) {
3666 LOGE("failed to get first element from bucket");
3670 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3672 LOGE("failed to get pad from first element");
3676 /* create ghostpad */
3677 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3678 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3679 LOGE("failed to add ghostpad to videobin");
3682 gst_object_unref(pad);
3684 /* done. free allocated variables */
3685 g_list_free(element_bucket);
3689 return MM_ERROR_NONE;
3692 LOGE("ERROR : releasing videobin");
3693 g_list_free(element_bucket);
3696 gst_object_unref(GST_OBJECT(pad));
3698 /* release videobin with it's childs */
3699 if (videobin[MMPLAYER_V_BIN].gst)
3700 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3702 MMPLAYER_FREEIF(videobin);
3703 player->pipeline->videobin = NULL;
3705 return MM_ERROR_PLAYER_INTERNAL;
3709 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3711 GList *element_bucket = NULL;
3712 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3714 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3715 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3716 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3717 "signal-handoffs", FALSE,
3720 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3721 _mmplayer_add_signal_connection(player,
3722 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3723 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3725 G_CALLBACK(__mmplayer_update_subtitle),
3728 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3729 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3731 if (!player->play_subtitle) {
3732 LOGD("add textbin sink as sink element of whole pipeline.");
3733 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3736 /* adding created elements to bin */
3737 LOGD("adding created elements to bin");
3738 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3739 LOGE("failed to add elements");
3743 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3744 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3745 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3747 /* linking elements in the bucket by added order. */
3748 LOGD("Linking elements in the bucket by added order.");
3749 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3750 LOGE("failed to link elements");
3754 /* done. free allocated variables */
3755 g_list_free(element_bucket);
3757 if (textbin[MMPLAYER_T_QUEUE].gst) {
3759 GstPad *ghostpad = NULL;
3761 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3763 LOGE("failed to get sink pad of text queue");
3767 ghostpad = gst_ghost_pad_new("text_sink", pad);
3768 gst_object_unref(pad);
3771 LOGE("failed to create ghostpad of textbin");
3775 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3776 LOGE("failed to add ghostpad to textbin");
3777 gst_object_unref(ghostpad);
3782 return MM_ERROR_NONE;
3785 g_list_free(element_bucket);
3787 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3788 LOGE("remove textbin sink from sink list");
3789 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3792 /* release element at __mmplayer_gst_create_text_sink_bin */
3793 return MM_ERROR_PLAYER_INTERNAL;
3797 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3799 mmplayer_gst_element_t *textbin = NULL;
3800 GList *element_bucket = NULL;
3801 int surface_type = 0;
3806 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3809 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3811 LOGE("failed to allocate memory for textbin");
3812 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3816 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3817 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3818 if (!textbin[MMPLAYER_T_BIN].gst) {
3819 LOGE("failed to create textbin");
3824 player->pipeline->textbin = textbin;
3827 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3828 LOGD("surface type for subtitle : %d", surface_type);
3829 switch (surface_type) {
3830 case MM_DISPLAY_SURFACE_OVERLAY:
3831 case MM_DISPLAY_SURFACE_NULL:
3832 case MM_DISPLAY_SURFACE_REMOTE:
3833 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3834 LOGE("failed to make plain text elements");
3845 return MM_ERROR_NONE;
3849 LOGD("ERROR : releasing textbin");
3851 g_list_free(element_bucket);
3853 /* release signal */
3854 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3856 /* release element which are not added to bin */
3857 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3858 /* NOTE : skip bin */
3859 if (textbin[i].gst) {
3860 GstObject *parent = NULL;
3861 parent = gst_element_get_parent(textbin[i].gst);
3864 gst_object_unref(GST_OBJECT(textbin[i].gst));
3865 textbin[i].gst = NULL;
3867 gst_object_unref(GST_OBJECT(parent));
3872 /* release textbin with it's childs */
3873 if (textbin[MMPLAYER_T_BIN].gst)
3874 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3876 MMPLAYER_FREEIF(textbin);
3877 player->pipeline->textbin = NULL;
3880 return MM_ERROR_PLAYER_INTERNAL;
3884 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3886 mmplayer_gst_element_t *mainbin = NULL;
3887 mmplayer_gst_element_t *textbin = NULL;
3888 MMHandleType attrs = 0;
3889 GstElement *subsrc = NULL;
3890 GstElement *subparse = NULL;
3891 gchar *subtitle_uri = NULL;
3892 const gchar *charset = NULL;
3898 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3900 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3902 mainbin = player->pipeline->mainbin;
3904 attrs = MMPLAYER_GET_ATTRS(player);
3906 LOGE("cannot get content attribute");
3907 return MM_ERROR_PLAYER_INTERNAL;
3910 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3911 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3912 LOGE("subtitle uri is not proper filepath.");
3913 return MM_ERROR_PLAYER_INVALID_URI;
3916 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3917 LOGE("failed to get storage info of subtitle path");
3918 return MM_ERROR_PLAYER_INVALID_URI;
3921 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3923 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3924 player->subtitle_language_list = NULL;
3925 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3927 /* create the subtitle source */
3928 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3930 LOGE("failed to create filesrc element");
3933 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3935 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3936 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3938 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3939 LOGW("failed to add queue");
3940 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3941 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3942 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3947 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3949 LOGE("failed to create subparse element");
3953 charset = _mmplayer_get_charset(subtitle_uri);
3955 LOGD("detected charset is %s", charset);
3956 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3959 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3960 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3962 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3963 LOGW("failed to add subparse");
3964 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3965 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3966 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3970 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3971 LOGW("failed to link subsrc and subparse");
3975 player->play_subtitle = TRUE;
3976 player->adjust_subtitle_pos = 0;
3978 LOGD("play subtitle using subtitle file");
3980 if (player->pipeline->textbin == NULL) {
3981 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3982 LOGE("failed to create text sink bin. continuing without text");
3986 textbin = player->pipeline->textbin;
3988 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3989 LOGW("failed to add textbin");
3991 /* release signal */
3992 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3994 /* release textbin with it's childs */
3995 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3996 MMPLAYER_FREEIF(player->pipeline->textbin);
3997 player->pipeline->textbin = textbin = NULL;
4001 LOGD("link text input selector and textbin ghost pad");
4003 player->textsink_linked = 1;
4004 player->external_text_idx = 0;
4005 LOGI("textsink is linked");
4007 textbin = player->pipeline->textbin;
4008 LOGD("text bin has been created. reuse it.");
4009 player->external_text_idx = 1;
4012 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4013 LOGW("failed to link subparse and textbin");
4017 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4019 LOGE("failed to get sink pad from textsink to probe data");
4023 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4024 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4026 gst_object_unref(pad);
4029 /* create dot. for debugging */
4030 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4033 return MM_ERROR_NONE;
4036 /* release text pipeline resource */
4037 player->textsink_linked = 0;
4039 /* release signal */
4040 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4042 if (player->pipeline->textbin) {
4043 LOGE("remove textbin");
4045 /* release textbin with it's childs */
4046 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4047 MMPLAYER_FREEIF(player->pipeline->textbin);
4048 player->pipeline->textbin = NULL;
4052 /* release subtitle elem */
4053 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4054 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4056 return MM_ERROR_PLAYER_INTERNAL;
4060 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4062 mmplayer_t *player = (mmplayer_t *)data;
4063 MMMessageParamType msg = {0, };
4064 GstClockTime duration = 0;
4065 gpointer text = NULL;
4066 guint text_size = 0;
4067 gboolean ret = TRUE;
4068 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4072 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4073 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4075 if (player->is_subtitle_force_drop) {
4076 LOGW("subtitle is dropped forcedly.");
4080 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4081 text = mapinfo.data;
4082 text_size = mapinfo.size;
4084 if (player->set_mode.subtitle_off) {
4085 LOGD("subtitle is OFF.");
4089 if (!text || (text_size == 0)) {
4090 LOGD("There is no subtitle to be displayed.");
4094 msg.data = (void *)text;
4096 duration = GST_BUFFER_DURATION(buffer);
4098 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4099 if (player->duration > GST_BUFFER_PTS(buffer))
4100 duration = player->duration - GST_BUFFER_PTS(buffer);
4103 LOGI("subtitle duration is invalid, subtitle duration change "
4104 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4106 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4108 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4110 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4111 gst_buffer_unmap(buffer, &mapinfo);
4118 static GstPadProbeReturn
4119 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4121 mmplayer_t *player = (mmplayer_t *)u_data;
4122 GstClockTime cur_timestamp = 0;
4123 gint64 adjusted_timestamp = 0;
4124 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4126 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4128 if (player->set_mode.subtitle_off) {
4129 LOGD("subtitle is OFF.");
4133 if (player->adjust_subtitle_pos == 0) {
4134 LOGD("nothing to do");
4138 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4139 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4141 if (adjusted_timestamp < 0) {
4142 LOGD("adjusted_timestamp under zero");
4147 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4148 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4149 GST_TIME_ARGS(cur_timestamp),
4150 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4152 return GST_PAD_PROBE_OK;
4156 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4160 /* check player and subtitlebin are created */
4161 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4162 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4164 if (position == 0) {
4165 LOGD("nothing to do");
4167 return MM_ERROR_NONE;
4170 /* check current postion */
4171 player->adjust_subtitle_pos = position;
4173 LOGD("save adjust_subtitle_pos in player");
4177 return MM_ERROR_NONE;
4181 * This function is to create audio or video pipeline for playing.
4183 * @param player [in] handle of player
4185 * @return This function returns zero on success.
4190 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4192 int ret = MM_ERROR_NONE;
4193 mmplayer_gst_element_t *mainbin = NULL;
4194 MMHandleType attrs = 0;
4197 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4199 /* get profile attribute */
4200 attrs = MMPLAYER_GET_ATTRS(player);
4202 LOGE("failed to get content attribute");
4206 /* create pipeline handles */
4207 if (player->pipeline) {
4208 LOGE("pipeline should be released before create new one");
4212 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4214 /* create mainbin */
4215 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4216 if (mainbin == NULL)
4219 /* create pipeline */
4220 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4221 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4222 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4223 LOGE("failed to create pipeline");
4228 player->pipeline->mainbin = mainbin;
4230 /* create the source and decoder elements */
4231 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4232 ret = _mmplayer_gst_build_es_pipeline(player);
4234 if (MMPLAYER_USE_DECODEBIN(player))
4235 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4237 ret = _mmplayer_gst_build_pipeline_with_src(player);
4240 if (ret != MM_ERROR_NONE) {
4241 LOGE("failed to create some elements");
4245 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4246 if (__mmplayer_check_subtitle(player)
4247 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4248 LOGE("failed to create text pipeline");
4251 ret = _mmplayer_gst_add_bus_watch(player);
4252 if (ret != MM_ERROR_NONE) {
4253 LOGE("failed to add bus watch");
4258 return MM_ERROR_NONE;
4261 _mmplayer_bus_watcher_remove(player);
4262 __mmplayer_gst_destroy_pipeline(player);
4263 return MM_ERROR_PLAYER_INTERNAL;
4267 __mmplayer_reset_gapless_state(mmplayer_t *player)
4270 MMPLAYER_RETURN_IF_FAIL(player
4272 && player->pipeline->audiobin
4273 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4275 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4282 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4285 int ret = MM_ERROR_NONE;
4289 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4291 /* cleanup stuffs */
4292 MMPLAYER_FREEIF(player->type);
4293 player->no_more_pad = FALSE;
4294 player->num_dynamic_pad = 0;
4296 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4297 player->subtitle_language_list = NULL;
4298 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4300 MMPLAYER_RECONFIGURE_LOCK(player);
4301 __mmplayer_reset_gapless_state(player);
4302 MMPLAYER_RECONFIGURE_UNLOCK(player);
4304 if (player->streamer) {
4305 _mm_player_streaming_initialize(player->streamer, FALSE);
4306 _mm_player_streaming_destroy(player->streamer);
4307 player->streamer = NULL;
4310 /* cleanup unlinked mime type */
4311 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4312 MMPLAYER_FREEIF(player->unlinked_video_mime);
4313 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4315 /* cleanup running stuffs */
4316 _mmplayer_cancel_eos_timer(player);
4318 /* cleanup gst stuffs */
4319 if (player->pipeline) {
4320 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4321 GstTagList *tag_list = player->pipeline->tag_list;
4323 /* first we need to disconnect all signal hander */
4324 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4327 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4328 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4329 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4330 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4331 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4332 gst_object_unref(bus);
4334 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4335 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4336 if (ret != MM_ERROR_NONE) {
4337 LOGE("fail to change state to NULL");
4338 return MM_ERROR_PLAYER_INTERNAL;
4341 LOGW("succeeded in changing state to NULL");
4343 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4346 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4347 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4349 /* free avsysaudiosink
4350 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4351 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4353 MMPLAYER_FREEIF(audiobin);
4354 MMPLAYER_FREEIF(videobin);
4355 MMPLAYER_FREEIF(textbin);
4356 MMPLAYER_FREEIF(mainbin);
4360 gst_tag_list_unref(tag_list);
4362 MMPLAYER_FREEIF(player->pipeline);
4364 MMPLAYER_FREEIF(player->album_art);
4366 if (player->type_caps) {
4367 gst_caps_unref(player->type_caps);
4368 player->type_caps = NULL;
4371 if (player->v_stream_caps) {
4372 gst_caps_unref(player->v_stream_caps);
4373 player->v_stream_caps = NULL;
4376 if (player->a_stream_caps) {
4377 gst_caps_unref(player->a_stream_caps);
4378 player->a_stream_caps = NULL;
4381 if (player->s_stream_caps) {
4382 gst_caps_unref(player->s_stream_caps);
4383 player->s_stream_caps = NULL;
4385 _mmplayer_track_destroy(player);
4387 if (player->sink_elements)
4388 g_list_free(player->sink_elements);
4389 player->sink_elements = NULL;
4391 if (player->bufmgr) {
4392 tbm_bufmgr_deinit(player->bufmgr);
4393 player->bufmgr = NULL;
4396 LOGW("finished destroy pipeline");
4404 __mmplayer_gst_realize(mmplayer_t *player)
4407 int ret = MM_ERROR_NONE;
4411 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4413 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4415 ret = __mmplayer_gst_create_pipeline(player);
4417 LOGE("failed to create pipeline");
4421 /* set pipeline state to READY */
4422 /* NOTE : state change to READY must be performed sync. */
4423 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4424 ret = _mmplayer_gst_set_state(player,
4425 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4427 if (ret != MM_ERROR_NONE) {
4428 /* return error if failed to set state */
4429 LOGE("failed to set READY state");
4433 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4435 /* create dot before error-return. for debugging */
4436 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4444 __mmplayer_gst_unrealize(mmplayer_t *player)
4446 int ret = MM_ERROR_NONE;
4450 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4452 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4453 MMPLAYER_PRINT_STATE(player);
4455 /* release miscellaneous information */
4456 __mmplayer_release_misc(player);
4458 /* destroy pipeline */
4459 ret = __mmplayer_gst_destroy_pipeline(player);
4460 if (ret != MM_ERROR_NONE) {
4461 LOGE("failed to destory pipeline");
4465 /* release miscellaneous information.
4466 these info needs to be released after pipeline is destroyed. */
4467 __mmplayer_release_misc_post(player);
4469 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4477 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4482 LOGW("set_message_callback is called with invalid player handle");
4483 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4486 player->msg_cb = callback;
4487 player->msg_cb_param = user_param;
4489 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4493 return MM_ERROR_NONE;
4497 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4499 int ret = MM_ERROR_NONE;
4504 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4505 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4506 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4508 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4510 if (strstr(uri, "es_buff://")) {
4511 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4512 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4513 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4514 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4516 tmp = g_ascii_strdown(uri, strlen(uri));
4517 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4518 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4520 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4522 } else if (strstr(uri, "mms://")) {
4523 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4524 } else if ((path = strstr(uri, "mem://"))) {
4525 ret = __mmplayer_set_mem_uri(data, path, param);
4527 ret = __mmplayer_set_file_uri(data, uri);
4530 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4531 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4532 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4533 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4535 /* dump parse result */
4536 SECURE_LOGW("incoming uri : %s", uri);
4537 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4538 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4546 __mmplayer_can_do_interrupt(mmplayer_t *player)
4548 if (!player || !player->pipeline || !player->attrs) {
4549 LOGW("not initialized");
4553 if (player->audio_decoded_cb) {
4554 LOGW("not support in pcm extraction mode");
4558 /* check if seeking */
4559 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4560 MMMessageParamType msg_param;
4561 memset(&msg_param, 0, sizeof(MMMessageParamType));
4562 msg_param.code = MM_ERROR_PLAYER_SEEK;
4563 player->seek_state = MMPLAYER_SEEK_NONE;
4564 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4568 /* check other thread */
4569 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4570 LOGW("locked already, cmd state : %d", player->cmd);
4572 /* check application command */
4573 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4574 LOGW("playing.. should wait cmd lock then, will be interrupted");
4576 /* lock will be released at mrp_resource_release_cb() */
4577 MMPLAYER_CMD_LOCK(player);
4580 LOGW("nothing to do");
4583 LOGW("can interrupt immediately");
4587 FAILED: /* with CMD UNLOCKED */
4590 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4595 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4598 mmplayer_t *player = NULL;
4599 MMMessageParamType msg = {0, };
4601 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4606 LOGE("user_data is null");
4609 player = (mmplayer_t *)user_data;
4611 if (!__mmplayer_can_do_interrupt(player)) {
4612 LOGW("no need to interrupt, so leave");
4613 /* FIXME: there is no way to avoid releasing resource. */
4617 player->interrupted_by_resource = TRUE;
4619 /* get last play position */
4620 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4621 msg.union_type = MM_MSG_UNION_TIME;
4622 msg.time.elapsed = pos;
4623 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4625 LOGW("failed to get play position.");
4628 LOGD("video resource conflict so, resource will be freed by unrealizing");
4629 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4630 LOGE("failed to unrealize");
4632 /* lock is called in __mmplayer_can_do_interrupt() */
4633 MMPLAYER_CMD_UNLOCK(player);
4635 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4636 player->hw_resource[res_idx] = NULL;
4640 return TRUE; /* release all the resources */
4644 __mmplayer_initialize_video_roi(mmplayer_t *player)
4646 player->video_roi.scale_x = 0.0;
4647 player->video_roi.scale_y = 0.0;
4648 player->video_roi.scale_width = 1.0;
4649 player->video_roi.scale_height = 1.0;
4653 _mmplayer_create_player(MMHandleType handle)
4655 int ret = MM_ERROR_PLAYER_INTERNAL;
4656 bool enabled = false;
4658 mmplayer_t *player = MM_PLAYER_CAST(handle);
4662 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4664 /* initialize player state */
4665 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4666 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4667 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4668 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4670 /* check current state */
4671 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4673 /* construct attributes */
4674 player->attrs = _mmplayer_construct_attribute(handle);
4676 if (!player->attrs) {
4677 LOGE("Failed to construct attributes");
4681 /* initialize gstreamer with configured parameter */
4682 if (!__mmplayer_init_gstreamer(player)) {
4683 LOGE("Initializing gstreamer failed");
4684 _mmplayer_deconstruct_attribute(handle);
4688 /* create lock. note that g_tread_init() has already called in gst_init() */
4689 g_mutex_init(&player->fsink_lock);
4691 /* create update tag lock */
4692 g_mutex_init(&player->update_tag_lock);
4694 /* create gapless play mutex */
4695 g_mutex_init(&player->gapless_play_thread_mutex);
4697 /* create gapless play cond */
4698 g_cond_init(&player->gapless_play_thread_cond);
4700 /* create gapless play thread */
4701 player->gapless_play_thread =
4702 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4703 if (!player->gapless_play_thread) {
4704 LOGE("failed to create gapless play thread");
4705 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4706 g_mutex_clear(&player->gapless_play_thread_mutex);
4707 g_cond_clear(&player->gapless_play_thread_cond);
4711 player->bus_msg_q = g_queue_new();
4712 if (!player->bus_msg_q) {
4713 LOGE("failed to create queue for bus_msg");
4714 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4718 ret = _mmplayer_initialize_video_capture(player);
4719 if (ret != MM_ERROR_NONE) {
4720 LOGE("failed to initialize video capture");
4724 /* initialize resource manager */
4725 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4726 __resource_release_cb, player, &player->resource_manager)
4727 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4728 LOGE("failed to initialize resource manager");
4729 ret = MM_ERROR_PLAYER_INTERNAL;
4733 /* create video bo lock and cond */
4734 g_mutex_init(&player->video_bo_mutex);
4735 g_cond_init(&player->video_bo_cond);
4737 /* create subtitle info lock and cond */
4738 g_mutex_init(&player->subtitle_info_mutex);
4739 g_cond_init(&player->subtitle_info_cond);
4741 player->streaming_type = STREAMING_SERVICE_NONE;
4743 /* give default value of audio effect setting */
4744 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4745 player->sound.rg_enable = false;
4746 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4748 player->play_subtitle = FALSE;
4749 player->has_closed_caption = FALSE;
4750 player->pending_resume = FALSE;
4751 if (player->ini.dump_element_keyword[0][0] == '\0')
4752 player->ini.set_dump_element_flag = FALSE;
4754 player->ini.set_dump_element_flag = TRUE;
4756 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4757 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4758 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4760 /* Set video360 settings to their defaults for just-created player.
4763 player->is_360_feature_enabled = FALSE;
4764 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4765 LOGI("spherical feature info: %d", enabled);
4767 player->is_360_feature_enabled = TRUE;
4769 LOGE("failed to get spherical feature info");
4772 player->is_content_spherical = FALSE;
4773 player->is_video360_enabled = TRUE;
4774 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4775 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4776 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4777 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4778 player->video360_zoom = 1.0f;
4779 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4780 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4782 __mmplayer_initialize_video_roi(player);
4784 /* set player state to null */
4785 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4786 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4790 return MM_ERROR_NONE;
4794 g_mutex_clear(&player->fsink_lock);
4795 /* free update tag lock */
4796 g_mutex_clear(&player->update_tag_lock);
4797 g_queue_free(player->bus_msg_q);
4798 player->bus_msg_q = NULL;
4799 /* free gapless play thread */
4800 if (player->gapless_play_thread) {
4801 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4802 player->gapless_play_thread_exit = TRUE;
4803 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4804 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4806 g_thread_join(player->gapless_play_thread);
4807 player->gapless_play_thread = NULL;
4809 g_mutex_clear(&player->gapless_play_thread_mutex);
4810 g_cond_clear(&player->gapless_play_thread_cond);
4813 /* release attributes */
4814 _mmplayer_deconstruct_attribute(handle);
4822 __mmplayer_init_gstreamer(mmplayer_t *player)
4824 static gboolean initialized = FALSE;
4825 static const int max_argc = 50;
4827 gchar **argv = NULL;
4828 gchar **argv2 = NULL;
4834 LOGD("gstreamer already initialized.");
4839 argc = malloc(sizeof(int));
4840 argv = malloc(sizeof(gchar *) * max_argc);
4841 argv2 = malloc(sizeof(gchar *) * max_argc);
4843 if (!argc || !argv || !argv2)
4846 memset(argv, 0, sizeof(gchar *) * max_argc);
4847 memset(argv2, 0, sizeof(gchar *) * max_argc);
4851 argv[0] = g_strdup("mmplayer");
4854 for (i = 0; i < 5; i++) {
4855 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4856 if (strlen(player->ini.gst_param[i]) > 0) {
4857 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4862 /* we would not do fork for scanning plugins */
4863 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4866 /* check disable registry scan */
4867 if (player->ini.skip_rescan) {
4868 argv[*argc] = g_strdup("--gst-disable-registry-update");
4872 /* check disable segtrap */
4873 if (player->ini.disable_segtrap) {
4874 argv[*argc] = g_strdup("--gst-disable-segtrap");
4878 LOGD("initializing gstreamer with following parameter");
4879 LOGD("argc : %d", *argc);
4882 for (i = 0; i < arg_count; i++) {
4884 LOGD("argv[%d] : %s", i, argv2[i]);
4887 /* initializing gstreamer */
4888 if (!gst_init_check(argc, &argv, &err)) {
4889 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4896 for (i = 0; i < arg_count; i++) {
4898 LOGD("release - argv[%d] : %s", i, argv2[i]);
4900 MMPLAYER_FREEIF(argv2[i]);
4903 MMPLAYER_FREEIF(argv);
4904 MMPLAYER_FREEIF(argv2);
4905 MMPLAYER_FREEIF(argc);
4915 for (i = 0; i < arg_count; i++) {
4916 LOGD("free[%d] : %s", i, argv2[i]);
4917 MMPLAYER_FREEIF(argv2[i]);
4920 MMPLAYER_FREEIF(argv);
4921 MMPLAYER_FREEIF(argv2);
4922 MMPLAYER_FREEIF(argc);
4928 __mmplayer_check_async_state_transition(mmplayer_t *player)
4930 GstState element_state = GST_STATE_VOID_PENDING;
4931 GstState element_pending_state = GST_STATE_VOID_PENDING;
4932 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4933 GstElement *element = NULL;
4934 gboolean async = FALSE;
4936 /* check player handle */
4937 MMPLAYER_RETURN_IF_FAIL(player &&
4939 player->pipeline->mainbin &&
4940 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4943 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4945 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4946 LOGD("don't need to check the pipeline state");
4950 MMPLAYER_PRINT_STATE(player);
4952 /* wait for state transition */
4953 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4954 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4956 if (ret == GST_STATE_CHANGE_FAILURE) {
4957 LOGE(" [%s] state : %s pending : %s",
4958 GST_ELEMENT_NAME(element),
4959 gst_element_state_get_name(element_state),
4960 gst_element_state_get_name(element_pending_state));
4962 /* dump state of all element */
4963 _mmplayer_dump_pipeline_state(player);
4968 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4973 _mmplayer_destroy(MMHandleType handle)
4975 mmplayer_t *player = MM_PLAYER_CAST(handle);
4979 /* check player handle */
4980 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4982 /* destroy can called at anytime */
4983 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4985 /* check async state transition */
4986 __mmplayer_check_async_state_transition(player);
4988 /* release gapless play thread */
4989 if (player->gapless_play_thread) {
4990 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4991 player->gapless_play_thread_exit = TRUE;
4992 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4993 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4995 LOGD("waitting for gapless play thread exit");
4996 g_thread_join(player->gapless_play_thread);
4997 g_mutex_clear(&player->gapless_play_thread_mutex);
4998 g_cond_clear(&player->gapless_play_thread_cond);
4999 LOGD("gapless play thread released");
5002 _mmplayer_release_video_capture(player);
5004 /* de-initialize resource manager */
5005 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
5006 player->resource_manager))
5007 LOGE("failed to deinitialize resource manager");
5009 /* release miscellaneous information */
5010 __mmplayer_release_misc(player);
5012 /* release pipeline */
5013 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
5014 LOGE("failed to destory pipeline");
5015 return MM_ERROR_PLAYER_INTERNAL;
5018 g_queue_free(player->bus_msg_q);
5020 /* release subtitle info lock and cond */
5021 g_mutex_clear(&player->subtitle_info_mutex);
5022 g_cond_clear(&player->subtitle_info_cond);
5024 __mmplayer_release_dump_list(player->dump_list);
5026 /* release miscellaneous information.
5027 these info needs to be released after pipeline is destroyed. */
5028 __mmplayer_release_misc_post(player);
5030 /* release attributes */
5031 _mmplayer_deconstruct_attribute(handle);
5033 if (player->uri_info.uri_list) {
5034 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5035 player->uri_info.uri_list = NULL;
5039 g_mutex_clear(&player->fsink_lock);
5042 g_mutex_clear(&player->update_tag_lock);
5044 /* release video bo lock and cond */
5045 g_mutex_clear(&player->video_bo_mutex);
5046 g_cond_clear(&player->video_bo_cond);
5050 return MM_ERROR_NONE;
5054 _mmplayer_realize(MMHandleType hplayer)
5056 mmplayer_t *player = (mmplayer_t *)hplayer;
5057 int ret = MM_ERROR_NONE;
5060 MMHandleType attrs = 0;
5064 /* check player handle */
5065 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5067 /* check current state */
5068 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5070 attrs = MMPLAYER_GET_ATTRS(player);
5072 LOGE("fail to get attributes.");
5073 return MM_ERROR_PLAYER_INTERNAL;
5075 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5076 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5078 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5079 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5081 if (ret != MM_ERROR_NONE) {
5082 LOGE("failed to parse profile");
5087 if (uri && (strstr(uri, "es_buff://"))) {
5088 if (strstr(uri, "es_buff://push_mode"))
5089 player->es_player_push_mode = TRUE;
5091 player->es_player_push_mode = FALSE;
5094 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5095 LOGW("mms protocol is not supported format.");
5096 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5099 if (MMPLAYER_IS_STREAMING(player))
5100 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5102 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5104 player->smooth_streaming = FALSE;
5105 player->videodec_linked = 0;
5106 player->audiodec_linked = 0;
5107 player->textsink_linked = 0;
5108 player->is_external_subtitle_present = FALSE;
5109 player->is_external_subtitle_added_now = FALSE;
5110 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5111 player->video360_metadata.is_spherical = -1;
5112 player->is_openal_plugin_used = FALSE;
5113 player->subtitle_language_list = NULL;
5114 player->is_subtitle_force_drop = FALSE;
5116 _mmplayer_track_initialize(player);
5117 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5119 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5120 gint prebuffer_ms = 0, rebuffer_ms = 0;
5122 player->streamer = _mm_player_streaming_create();
5123 _mm_player_streaming_initialize(player->streamer, TRUE);
5125 mm_attrs_multiple_get(player->attrs, NULL,
5126 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5127 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5129 if (prebuffer_ms > 0) {
5130 prebuffer_ms = MAX(prebuffer_ms, 1000);
5131 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5134 if (rebuffer_ms > 0) {
5135 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5136 rebuffer_ms = MAX(rebuffer_ms, 1000);
5137 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5140 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5141 player->streamer->buffering_req.rebuffer_time);
5144 /* realize pipeline */
5145 ret = __mmplayer_gst_realize(player);
5146 if (ret != MM_ERROR_NONE)
5147 LOGE("fail to realize the player.");
5149 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5157 _mmplayer_unrealize(MMHandleType hplayer)
5159 mmplayer_t *player = (mmplayer_t *)hplayer;
5160 int ret = MM_ERROR_NONE;
5164 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5166 MMPLAYER_CMD_UNLOCK(player);
5167 _mmplayer_bus_watcher_remove(player);
5168 /* destroy the gst bus msg thread which is created during realize.
5169 this funct have to be called before getting cmd lock. */
5170 _mmplayer_bus_msg_thread_destroy(player);
5171 MMPLAYER_CMD_LOCK(player);
5173 /* check current state */
5174 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5176 /* check async state transition */
5177 __mmplayer_check_async_state_transition(player);
5179 /* unrealize pipeline */
5180 ret = __mmplayer_gst_unrealize(player);
5182 if (!player->interrupted_by_resource) {
5183 int rm_ret = MM_ERROR_NONE;
5184 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5186 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5187 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5188 if (rm_ret != MM_ERROR_NONE)
5189 LOGE("failed to release [%d] resources", res_idx);
5198 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5200 mmplayer_t *player = (mmplayer_t *)hplayer;
5202 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5204 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5208 _mmplayer_get_state(MMHandleType hplayer, int *state)
5210 mmplayer_t *player = (mmplayer_t *)hplayer;
5212 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5214 *state = MMPLAYER_CURRENT_STATE(player);
5216 return MM_ERROR_NONE;
5220 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5222 GstElement *vol_element = NULL;
5223 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5226 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5227 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5229 /* check pipeline handle */
5230 if (!player->pipeline || !player->pipeline->audiobin) {
5231 LOGD("'%s' will be applied when audiobin is created", prop_name);
5233 /* NOTE : stored value will be used in create_audiobin
5234 * returning MM_ERROR_NONE here makes application to able to
5235 * set audio volume or mute at anytime.
5237 return MM_ERROR_NONE;
5240 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5241 volume_elem_id = MMPLAYER_A_SINK;
5243 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5245 LOGE("failed to get vol element %d", volume_elem_id);
5246 return MM_ERROR_PLAYER_INTERNAL;
5249 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5251 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5252 LOGE("there is no '%s' property", prop_name);
5253 return MM_ERROR_PLAYER_INTERNAL;
5256 if (!strcmp(prop_name, "volume")) {
5257 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5258 } else if (!strcmp(prop_name, "mute")) {
5259 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5261 LOGE("invalid property %s", prop_name);
5262 return MM_ERROR_PLAYER_INTERNAL;
5265 return MM_ERROR_NONE;
5269 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5271 int ret = MM_ERROR_NONE;
5272 mmplayer_t *player = (mmplayer_t *)hplayer;
5275 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5277 LOGD("volume = %f", volume);
5279 /* invalid factor range or not */
5280 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5281 LOGE("Invalid volume value");
5282 return MM_ERROR_INVALID_ARGUMENT;
5285 player->sound.volume = volume;
5287 ret = __mmplayer_gst_set_volume_property(player, "volume");
5294 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5296 mmplayer_t *player = (mmplayer_t *)hplayer;
5300 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5301 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5303 *volume = player->sound.volume;
5305 LOGD("current vol = %f", *volume);
5308 return MM_ERROR_NONE;
5312 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5314 int ret = MM_ERROR_NONE;
5315 mmplayer_t *player = (mmplayer_t *)hplayer;
5318 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5320 LOGD("mute = %d", mute);
5322 player->sound.mute = mute;
5324 ret = __mmplayer_gst_set_volume_property(player, "mute");
5331 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5333 mmplayer_t *player = (mmplayer_t *)hplayer;
5337 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5338 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5340 *mute = player->sound.mute;
5342 LOGD("current mute = %d", *mute);
5346 return MM_ERROR_NONE;
5350 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5352 mmplayer_t *player = (mmplayer_t *)hplayer;
5356 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5358 player->audio_stream_changed_cb = callback;
5359 player->audio_stream_changed_cb_user_param = user_param;
5360 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5364 return MM_ERROR_NONE;
5368 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5370 mmplayer_t *player = (mmplayer_t *)hplayer;
5374 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5376 player->audio_decoded_cb = callback;
5377 player->audio_decoded_cb_user_param = user_param;
5378 player->audio_extract_opt = opt;
5379 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5383 return MM_ERROR_NONE;
5387 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5389 mmplayer_t *player = (mmplayer_t *)hplayer;
5393 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5395 if (callback && !player->bufmgr)
5396 player->bufmgr = tbm_bufmgr_init(-1);
5398 player->set_mode.video_export = (callback) ? true : false;
5399 player->video_decoded_cb = callback;
5400 player->video_decoded_cb_user_param = user_param;
5402 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5406 return MM_ERROR_NONE;
5410 _mmplayer_start(MMHandleType hplayer)
5412 mmplayer_t *player = (mmplayer_t *)hplayer;
5413 gint ret = MM_ERROR_NONE;
5417 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5419 /* check current state */
5420 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5422 /* start pipeline */
5423 ret = _mmplayer_gst_start(player);
5424 if (ret != MM_ERROR_NONE)
5425 LOGE("failed to start player.");
5427 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5428 LOGD("force playing start even during buffering");
5429 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5437 /* NOTE: post "not supported codec message" to application
5438 * when one codec is not found during AUTOPLUGGING in MSL.
5439 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5440 * And, if any codec is not found, don't send message here.
5441 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5444 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5446 MMMessageParamType msg_param;
5447 memset(&msg_param, 0, sizeof(MMMessageParamType));
5448 gboolean post_msg_direct = FALSE;
5452 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5454 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5455 player->not_supported_codec, player->can_support_codec);
5457 if (player->not_found_demuxer) {
5458 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5459 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5461 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5462 MMPLAYER_FREEIF(msg_param.data);
5464 return MM_ERROR_NONE;
5467 if (player->not_supported_codec) {
5468 if (player->can_support_codec) {
5469 // There is one codec to play
5470 post_msg_direct = TRUE;
5472 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5473 post_msg_direct = TRUE;
5476 if (post_msg_direct) {
5477 MMMessageParamType msg_param;
5478 memset(&msg_param, 0, sizeof(MMMessageParamType));
5480 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5481 LOGW("not found AUDIO codec, posting error code to application.");
5483 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5484 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5485 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5486 LOGW("not found VIDEO codec, posting error code to application.");
5488 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5489 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5492 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5494 MMPLAYER_FREEIF(msg_param.data);
5496 return MM_ERROR_NONE;
5498 // no any supported codec case
5499 LOGW("not found any codec, posting error code to application.");
5501 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5502 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5503 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5505 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5506 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5509 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5511 MMPLAYER_FREEIF(msg_param.data);
5517 return MM_ERROR_NONE;
5520 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5522 GstState element_state = GST_STATE_VOID_PENDING;
5523 GstState element_pending_state = GST_STATE_VOID_PENDING;
5524 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5525 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5527 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5529 MMPLAYER_RECONFIGURE_LOCK(player);
5530 if (!player->gapless.reconfigure) {
5531 MMPLAYER_RECONFIGURE_UNLOCK(player);
5535 LOGI("reconfigure is under process");
5536 MMPLAYER_RECONFIGURE_WAIT(player);
5537 MMPLAYER_RECONFIGURE_UNLOCK(player);
5538 LOGI("reconfigure is completed.");
5540 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5541 &element_state, &element_pending_state, timeout * GST_SECOND);
5542 if (result == GST_STATE_CHANGE_FAILURE)
5543 LOGW("failed to get pipeline state in %d sec", timeout);
5548 /* NOTE : it should be able to call 'stop' anytime*/
5550 _mmplayer_stop(MMHandleType hplayer)
5552 mmplayer_t *player = (mmplayer_t *)hplayer;
5553 int ret = MM_ERROR_NONE;
5557 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5559 /* check current state */
5560 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5562 /* need to wait till the rebuilding pipeline is completed */
5563 __mmplayer_check_pipeline_reconfigure_state(player);
5564 MMPLAYER_RECONFIGURE_LOCK(player);
5565 __mmplayer_reset_gapless_state(player);
5566 MMPLAYER_RECONFIGURE_UNLOCK(player);
5568 /* NOTE : application should not wait for EOS after calling STOP */
5569 _mmplayer_cancel_eos_timer(player);
5572 player->seek_state = MMPLAYER_SEEK_NONE;
5575 ret = _mmplayer_gst_stop(player);
5577 if (ret != MM_ERROR_NONE)
5578 LOGE("failed to stop player.");
5586 _mmplayer_pause(MMHandleType hplayer)
5588 mmplayer_t *player = (mmplayer_t *)hplayer;
5589 gint64 pos_nsec = 0;
5590 gboolean async = FALSE;
5591 gint ret = MM_ERROR_NONE;
5595 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5597 /* check current state */
5598 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5600 /* check pipline reconfigure state */
5601 __mmplayer_check_pipeline_reconfigure_state(player);
5603 switch (MMPLAYER_CURRENT_STATE(player)) {
5604 case MM_PLAYER_STATE_READY:
5606 /* check prepare async or not.
5607 * In the case of streaming playback, it's recommned to avoid blocking wait.
5609 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5610 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5612 /* Changing back sync of rtspsrc to async */
5613 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5614 LOGD("async prepare working mode for rtsp");
5620 case MM_PLAYER_STATE_PLAYING:
5622 /* NOTE : store current point to overcome some bad operation
5623 *(returning zero when getting current position in paused state) of some
5626 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5627 LOGW("getting current position failed in paused");
5629 player->last_position = pos_nsec;
5631 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5632 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5633 This causes problem is position calculation during normal pause resume scenarios also.
5634 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5635 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5636 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5637 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5643 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5644 LOGD("doing async pause in case of ms buff src");
5648 /* pause pipeline */
5649 ret = _mmplayer_gst_pause(player, async);
5651 if (ret != MM_ERROR_NONE)
5652 LOGE("failed to pause player. ret : 0x%x", ret);
5654 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5655 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5656 LOGE("failed to update display_rotation");
5664 /* in case of streaming, pause could take long time.*/
5666 _mmplayer_abort_pause(MMHandleType hplayer)
5668 mmplayer_t *player = (mmplayer_t *)hplayer;
5669 int ret = MM_ERROR_NONE;
5673 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5675 player->pipeline->mainbin,
5676 MM_ERROR_PLAYER_NOT_INITIALIZED);
5678 LOGD("set the pipeline state to READY");
5680 /* set state to READY */
5681 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5682 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5683 if (ret != MM_ERROR_NONE) {
5684 LOGE("fail to change state to READY");
5685 return MM_ERROR_PLAYER_INTERNAL;
5688 LOGD("succeeded in changing state to READY");
5693 _mmplayer_resume(MMHandleType hplayer)
5695 mmplayer_t *player = (mmplayer_t *)hplayer;
5696 int ret = MM_ERROR_NONE;
5697 gboolean async = FALSE;
5701 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5703 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5704 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5705 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5709 /* Changing back sync mode rtspsrc to async */
5710 LOGD("async resume for rtsp case");
5714 /* check current state */
5715 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5717 ret = _mmplayer_gst_resume(player, async);
5718 if (ret != MM_ERROR_NONE)
5719 LOGE("failed to resume player.");
5721 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5722 LOGD("force resume even during buffering");
5723 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5732 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5734 mmplayer_t *player = (mmplayer_t *)hplayer;
5735 gint64 pos_nsec = 0;
5736 int ret = MM_ERROR_NONE;
5738 signed long long start = 0, stop = 0;
5739 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5742 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5743 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5745 /* The sound of video is not supported under 0.0 and over 2.0. */
5746 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5747 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5750 _mmplayer_set_mute(hplayer, mute);
5752 if (player->playback_rate == rate)
5753 return MM_ERROR_NONE;
5755 /* If the position is reached at start potion during fast backward, EOS is posted.
5756 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5758 player->playback_rate = rate;
5760 current_state = MMPLAYER_CURRENT_STATE(player);
5762 if (current_state != MM_PLAYER_STATE_PAUSED)
5763 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5765 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5767 if ((current_state == MM_PLAYER_STATE_PAUSED)
5768 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5769 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5770 pos_nsec = player->last_position;
5775 stop = GST_CLOCK_TIME_NONE;
5777 start = GST_CLOCK_TIME_NONE;
5781 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5782 player->playback_rate,
5784 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5785 GST_SEEK_TYPE_SET, start,
5786 GST_SEEK_TYPE_SET, stop)) {
5787 LOGE("failed to set speed playback");
5788 return MM_ERROR_PLAYER_SEEK;
5791 LOGD("succeeded to set speed playback as %0.1f", rate);
5795 return MM_ERROR_NONE;;
5799 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5801 mmplayer_t *player = (mmplayer_t *)hplayer;
5802 int ret = MM_ERROR_NONE;
5806 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5808 /* check pipline reconfigure state */
5809 __mmplayer_check_pipeline_reconfigure_state(player);
5811 ret = _mmplayer_gst_set_position(player, position, FALSE);
5819 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5821 mmplayer_t *player = (mmplayer_t *)hplayer;
5822 int ret = MM_ERROR_NONE;
5824 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5825 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5827 if (g_strrstr(player->type, "video/mpegts"))
5828 __mmplayer_update_duration_value(player);
5830 *duration = player->duration;
5835 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5837 mmplayer_t *player = (mmplayer_t *)hplayer;
5838 int ret = MM_ERROR_NONE;
5840 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5842 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5848 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5850 mmplayer_t *player = (mmplayer_t *)hplayer;
5851 int ret = MM_ERROR_NONE;
5855 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5857 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5865 __mmplayer_is_midi_type(gchar *str_caps)
5867 if ((g_strrstr(str_caps, "audio/midi")) ||
5868 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5869 (g_strrstr(str_caps, "application/x-smaf")) ||
5870 (g_strrstr(str_caps, "audio/x-imelody")) ||
5871 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5872 (g_strrstr(str_caps, "audio/xmf")) ||
5873 (g_strrstr(str_caps, "audio/mxmf"))) {
5882 __mmplayer_is_only_mp3_type(gchar *str_caps)
5884 if (g_strrstr(str_caps, "application/x-id3") ||
5885 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5891 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5893 GstStructure *caps_structure = NULL;
5894 gint samplerate = 0;
5898 MMPLAYER_RETURN_IF_FAIL(player && caps);
5900 caps_structure = gst_caps_get_structure(caps, 0);
5902 /* set stream information */
5903 gst_structure_get_int(caps_structure, "rate", &samplerate);
5904 gst_structure_get_int(caps_structure, "channels", &channels);
5906 mm_player_set_attribute((MMHandleType)player, NULL,
5907 "content_audio_samplerate", samplerate,
5908 "content_audio_channels", channels, NULL);
5910 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5914 __mmplayer_update_content_type_info(mmplayer_t *player)
5917 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5919 if (__mmplayer_is_midi_type(player->type)) {
5920 player->bypass_audio_effect = TRUE;
5924 if (!player->streamer) {
5925 LOGD("no need to check streaming type");
5929 if (g_strrstr(player->type, "application/x-hls")) {
5930 /* If it can't know exact type when it parses uri because of redirection case,
5931 * it will be fixed by typefinder or when doing autoplugging.
5933 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5934 player->streamer->is_adaptive_streaming = TRUE;
5935 } else if (g_strrstr(player->type, "application/dash+xml")) {
5936 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5937 player->streamer->is_adaptive_streaming = TRUE;
5940 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5941 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5942 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5944 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5945 if (player->streamer->is_adaptive_streaming)
5946 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5948 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5952 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5957 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5958 GstCaps *caps, gpointer data)
5960 mmplayer_t *player = (mmplayer_t *)data;
5964 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5966 /* store type string */
5967 if (player->type_caps) {
5968 gst_caps_unref(player->type_caps);
5969 player->type_caps = NULL;
5972 player->type_caps = gst_caps_copy(caps);
5973 MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
5975 MMPLAYER_FREEIF(player->type);
5976 player->type = gst_caps_to_string(caps);
5978 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5979 player, player->type, probability, gst_caps_get_size(caps));
5981 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5982 (g_strrstr(player->type, "audio/x-raw-int"))) {
5983 LOGE("not support media format");
5985 if (player->msg_posted == FALSE) {
5986 MMMessageParamType msg_param;
5987 memset(&msg_param, 0, sizeof(MMMessageParamType));
5989 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5990 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5992 /* don't post more if one was sent already */
5993 player->msg_posted = TRUE;
5998 __mmplayer_update_content_type_info(player);
6000 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
6003 pad = gst_element_get_static_pad(tf, "src");
6005 LOGE("fail to get typefind src pad.");
6009 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6010 gboolean async = FALSE;
6011 LOGE("failed to autoplug %s", player->type);
6013 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6015 if (async && player->msg_posted == FALSE)
6016 __mmplayer_handle_missed_plugin(player);
6018 gst_object_unref(GST_OBJECT(pad));
6025 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6027 GstElement *decodebin = NULL;
6031 /* create decodebin */
6032 decodebin = gst_element_factory_make("decodebin", NULL);
6035 LOGE("fail to create decodebin");
6039 /* raw pad handling signal */
6040 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6041 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6043 /* no-more-pad pad handling signal */
6044 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6045 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6047 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6048 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6050 /* This signal is emitted when a pad for which there is no further possible
6051 decoding is added to the decodebin.*/
6052 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6053 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6055 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6056 before looking for any elements that can handle that stream.*/
6057 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6058 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6060 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6061 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6062 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6064 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6065 before looking for any elements that can handle that stream.*/
6066 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6067 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6069 /* This signal is emitted once decodebin has finished decoding all the data.*/
6070 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6071 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6073 /* This signal is emitted when a element is added to the bin.*/
6074 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6075 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6082 __mmplayer_gst_make_queue2(mmplayer_t *player)
6084 GstElement *queue2 = NULL;
6085 gint64 dur_bytes = 0L;
6086 mmplayer_gst_element_t *mainbin = NULL;
6087 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6090 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6092 mainbin = player->pipeline->mainbin;
6094 queue2 = gst_element_factory_make("queue2", "queue2");
6096 LOGE("failed to create buffering queue element");
6100 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6101 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6103 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6105 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6106 * skip the pull mode(file or ring buffering) setting. */
6107 if (dur_bytes > 0) {
6108 if (!g_strrstr(player->type, "video/mpegts")) {
6109 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6110 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6116 _mm_player_streaming_set_queue2(player->streamer,
6120 (guint64)dur_bytes); /* no meaning at the moment */
6126 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6128 mmplayer_gst_element_t *mainbin = NULL;
6129 GstElement *decodebin = NULL;
6130 GstElement *queue2 = NULL;
6131 GstPad *sinkpad = NULL;
6132 GstPad *qsrcpad = NULL;
6135 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6137 mainbin = player->pipeline->mainbin;
6139 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6141 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6142 LOGW("need to check: muxed buffer is not null");
6145 queue2 = __mmplayer_gst_make_queue2(player);
6147 LOGE("failed to make queue2");
6151 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6152 LOGE("failed to add buffering queue");
6156 sinkpad = gst_element_get_static_pad(queue2, "sink");
6157 qsrcpad = gst_element_get_static_pad(queue2, "src");
6159 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6160 LOGE("failed to link [%s:%s]-[%s:%s]",
6161 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6165 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6166 LOGE("failed to sync queue2 state with parent");
6170 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6171 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6175 gst_object_unref(GST_OBJECT(sinkpad));
6179 /* create decodebin */
6180 decodebin = _mmplayer_gst_make_decodebin(player);
6182 LOGE("failed to make decodebin");
6186 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6187 LOGE("failed to add decodebin");
6191 /* to force caps on the decodebin element and avoid reparsing stuff by
6192 * typefind. It also avoids a deadlock in the way typefind activates pads in
6193 * the state change */
6194 g_object_set(decodebin, "sink-caps", caps, NULL);
6196 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6198 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6199 LOGE("failed to link [%s:%s]-[%s:%s]",
6200 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6204 gst_object_unref(GST_OBJECT(sinkpad));
6206 gst_object_unref(GST_OBJECT(qsrcpad));
6209 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6210 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6212 /* set decodebin property about buffer in streaming playback. *
6213 * in case of HLS/DASH, it does not need to have big buffer *
6214 * because it is kind of adaptive streaming. */
6215 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6216 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6217 gint high_percent = 0;
6219 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6220 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6222 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6224 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6226 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6227 "high-percent", high_percent,
6228 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6229 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6230 "max-size-buffers", 0, NULL); // disable or automatic
6233 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6234 LOGE("failed to sync decodebin state with parent");
6245 gst_object_unref(GST_OBJECT(sinkpad));
6248 gst_object_unref(GST_OBJECT(qsrcpad));
6251 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6252 * You need to explicitly set elements to the NULL state before
6253 * dropping the final reference, to allow them to clean up.
6255 gst_element_set_state(queue2, GST_STATE_NULL);
6257 /* And, it still has a parent "player".
6258 * You need to let the parent manage the object instead of unreffing the object directly.
6260 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6261 gst_object_unref(queue2);
6266 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6267 * You need to explicitly set elements to the NULL state before
6268 * dropping the final reference, to allow them to clean up.
6270 gst_element_set_state(decodebin, GST_STATE_NULL);
6272 /* And, it still has a parent "player".
6273 * You need to let the parent manage the object instead of unreffing the object directly.
6276 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6277 gst_object_unref(decodebin);
6285 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6289 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6290 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6292 LOGD("class : %s, mime : %s", factory_class, mime);
6294 /* add missing plugin */
6295 /* NOTE : msl should check missing plugin for image mime type.
6296 * Some motion jpeg clips can have playable audio track.
6297 * So, msl have to play audio after displaying popup written video format not supported.
6299 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6300 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6301 LOGD("not found demuxer");
6302 player->not_found_demuxer = TRUE;
6303 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6309 if (!g_strrstr(factory_class, "Demuxer")) {
6310 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6311 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6312 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6314 /* check that clip have multi tracks or not */
6315 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6316 LOGD("video plugin is already linked");
6318 LOGW("add VIDEO to missing plugin");
6319 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6320 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6322 } else if (g_str_has_prefix(mime, "audio")) {
6323 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6324 LOGD("audio plugin is already linked");
6326 LOGW("add AUDIO to missing plugin");
6327 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6328 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6336 return MM_ERROR_NONE;
6340 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6342 mmplayer_t *player = (mmplayer_t *)data;
6346 MMPLAYER_RETURN_IF_FAIL(player);
6348 /* remove fakesink. */
6349 if (!_mmplayer_gst_remove_fakesink(player,
6350 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6351 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6352 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6353 * source element are not same. To overcome this situation, this function will called
6354 * several places and several times. Therefore, this is not an error case.
6359 LOGD("[handle: %p] pipeline has completely constructed", player);
6361 if ((player->msg_posted == FALSE) &&
6362 (player->cmd >= MMPLAYER_COMMAND_START))
6363 __mmplayer_handle_missed_plugin(player);
6365 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6369 __mmplayer_check_profile(void)
6372 static int profile_tv = -1;
6374 if (__builtin_expect(profile_tv != -1, 1))
6377 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6378 switch (*profileName) {
6393 __mmplayer_get_next_uri(mmplayer_t *player)
6395 mmplayer_parse_profile_t profile;
6397 guint num_of_list = 0;
6400 num_of_list = g_list_length(player->uri_info.uri_list);
6401 uri_idx = player->uri_info.uri_idx;
6403 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6404 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6405 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6407 LOGW("next uri does not exist");
6411 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6412 LOGE("failed to parse profile");
6416 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6417 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6418 LOGW("uri type is not supported(%d)", profile.uri_type);
6422 LOGD("success to find next uri %d", uri_idx);
6426 if (!uri || uri_idx == num_of_list) {
6427 LOGE("failed to find next uri");
6431 player->uri_info.uri_idx = uri_idx;
6432 if (mm_player_set_attribute((MMHandleType)player, NULL,
6433 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6434 LOGE("failed to set attribute");
6438 SECURE_LOGD("next playback uri: %s", uri);
6443 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6445 #define REPEAT_COUNT_INFINITE -1
6446 #define REPEAT_COUNT_MIN 2
6447 #define ORIGINAL_URI_ONLY 1
6449 MMHandleType attrs = 0;
6453 guint num_of_uri = 0;
6454 int profile_tv = -1;
6458 LOGD("checking for gapless play option");
6460 if (player->build_audio_offload) {
6461 LOGE("offload path is not supportable.");
6465 if (player->pipeline->textbin) {
6466 LOGE("subtitle path is enabled. gapless play is not supported.");
6470 attrs = MMPLAYER_GET_ATTRS(player);
6472 LOGE("fail to get attributes.");
6476 mm_attrs_multiple_get(player->attrs, NULL,
6477 "content_video_found", &video,
6478 "profile_play_count", &count,
6479 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6481 /* gapless playback is not supported in case of video at TV profile. */
6482 profile_tv = __mmplayer_check_profile();
6483 if (profile_tv && video) {
6484 LOGW("not support video gapless playback");
6488 /* check repeat count in case of audio */
6490 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6491 LOGW("gapless is disabled");
6495 num_of_uri = g_list_length(player->uri_info.uri_list);
6497 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6499 if (num_of_uri == ORIGINAL_URI_ONLY) {
6500 /* audio looping path */
6501 if (count >= REPEAT_COUNT_MIN) {
6502 /* decrease play count */
6503 /* we succeeded to rewind. update play count and then wait for next EOS */
6505 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6506 } else if (count != REPEAT_COUNT_INFINITE) {
6507 LOGD("there is no next uri and no repeat");
6510 LOGD("looping cnt %d", count);
6512 /* gapless playback path */
6513 if (!__mmplayer_get_next_uri(player)) {
6514 LOGE("failed to get next uri");
6521 LOGE("unable to play gapless path. EOS will be posted soon");
6526 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6528 GstPad *sinkpad = g_value_get_object (item);
6529 GstElement *element = GST_ELEMENT(user_data);
6530 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6531 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6535 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6537 mmplayer_gst_element_t *sinkbin = NULL;
6538 main_element_id_e concatId = MMPLAYER_M_NUM;
6539 main_element_id_e sinkId = MMPLAYER_M_NUM;
6540 gboolean send_notice = FALSE;
6541 GstElement *element;
6545 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6547 LOGD("type %d", type);
6550 case MM_PLAYER_TRACK_TYPE_AUDIO:
6551 concatId = MMPLAYER_M_A_CONCAT;
6552 sinkId = MMPLAYER_A_BIN;
6553 sinkbin = player->pipeline->audiobin;
6555 case MM_PLAYER_TRACK_TYPE_VIDEO:
6556 concatId = MMPLAYER_M_V_CONCAT;
6557 sinkId = MMPLAYER_V_BIN;
6558 sinkbin = player->pipeline->videobin;
6561 case MM_PLAYER_TRACK_TYPE_TEXT:
6562 concatId = MMPLAYER_M_T_CONCAT;
6563 sinkId = MMPLAYER_T_BIN;
6564 sinkbin = player->pipeline->textbin;
6567 LOGE("requested type is not supportable");
6572 element = player->pipeline->mainbin[concatId].gst;
6576 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6577 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6578 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6579 if (srcpad && sinkpad) {
6580 /* after getting drained signal there is no data flows, so no need to do pad_block */
6581 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6582 gst_pad_unlink(srcpad, sinkpad);
6584 /* send custom event to sink pad to handle it at video sink */
6586 LOGD("send custom event to sinkpad");
6587 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6588 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6589 gst_pad_send_event(sinkpad, event);
6592 gst_object_unref(srcpad);
6593 gst_object_unref(sinkpad);
6596 LOGD("release concat request pad");
6597 /* release and unref requests pad from the selector */
6598 iter = gst_element_iterate_sink_pads(element);
6599 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6600 gst_iterator_resync(iter);
6601 gst_iterator_free(iter);
6607 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6609 mmplayer_track_t *selector = &player->track[type];
6610 mmplayer_gst_element_t *sinkbin = NULL;
6611 main_element_id_e selectorId = MMPLAYER_M_NUM;
6612 main_element_id_e sinkId = MMPLAYER_M_NUM;
6613 GstPad *srcpad = NULL;
6614 GstPad *sinkpad = NULL;
6615 gboolean send_notice = FALSE;
6618 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6620 LOGD("type %d", type);
6623 case MM_PLAYER_TRACK_TYPE_AUDIO:
6624 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6625 sinkId = MMPLAYER_A_BIN;
6626 sinkbin = player->pipeline->audiobin;
6628 case MM_PLAYER_TRACK_TYPE_VIDEO:
6629 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6630 sinkId = MMPLAYER_V_BIN;
6631 sinkbin = player->pipeline->videobin;
6634 case MM_PLAYER_TRACK_TYPE_TEXT:
6635 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6636 sinkId = MMPLAYER_T_BIN;
6637 sinkbin = player->pipeline->textbin;
6640 LOGE("requested type is not supportable");
6645 if (player->pipeline->mainbin[selectorId].gst) {
6648 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6650 if (selector->event_probe_id != 0)
6651 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6652 selector->event_probe_id = 0;
6654 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6655 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6657 if (srcpad && sinkpad) {
6658 /* after getting drained signal there is no data flows, so no need to do pad_block */
6659 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6660 gst_pad_unlink(srcpad, sinkpad);
6662 /* send custom event to sink pad to handle it at video sink */
6664 LOGD("send custom event to sinkpad");
6665 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6666 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6667 gst_pad_send_event(sinkpad, event);
6671 gst_object_unref(sinkpad);
6674 gst_object_unref(srcpad);
6677 LOGD("selector release");
6679 /* release and unref requests pad from the selector */
6680 for (n = 0; n < selector->streams->len; n++) {
6681 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6682 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6685 g_ptr_array_set_size(selector->streams, 0);
6687 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6688 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6690 player->pipeline->mainbin[selectorId].gst = NULL;
6698 __mmplayer_deactivate_old_path(mmplayer_t *player)
6701 MMPLAYER_RETURN_IF_FAIL(player);
6703 if (MMPLAYER_USE_DECODEBIN(player)) {
6704 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6705 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6706 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6707 LOGE("deactivate selector error");
6711 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6712 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6713 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6714 LOGE("deactivate concat error");
6719 _mmplayer_track_destroy(player);
6720 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6722 if (player->streamer) {
6723 _mm_player_streaming_initialize(player->streamer, FALSE);
6724 _mm_player_streaming_destroy(player->streamer);
6725 player->streamer = NULL;
6728 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6734 if (!player->msg_posted) {
6735 MMMessageParamType msg = {0,};
6738 msg.code = MM_ERROR_PLAYER_INTERNAL;
6739 LOGE("gapless_uri_play> deactivate error");
6741 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6742 player->msg_posted = TRUE;
6748 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6750 int result = MM_ERROR_NONE;
6751 mmplayer_t *player = (mmplayer_t *)hplayer;
6754 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6755 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6757 if (mm_player_set_attribute(hplayer, NULL,
6758 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6759 LOGE("failed to set attribute");
6760 result = MM_ERROR_PLAYER_INTERNAL;
6762 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6763 LOGE("failed to add the original uri in the uri list.");
6771 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6773 mmplayer_t *player = (mmplayer_t *)hplayer;
6774 guint num_of_list = 0;
6778 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6779 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6781 if (player->pipeline && player->pipeline->textbin) {
6782 LOGE("subtitle path is enabled.");
6783 return MM_ERROR_PLAYER_INVALID_STATE;
6786 num_of_list = g_list_length(player->uri_info.uri_list);
6788 if (is_first_path) {
6789 if (num_of_list == 0) {
6790 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6791 SECURE_LOGD("add original path : %s", uri);
6793 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6794 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6796 SECURE_LOGD("change original path : %s", uri);
6799 MMHandleType attrs = 0;
6800 attrs = MMPLAYER_GET_ATTRS(player);
6802 if (num_of_list == 0) {
6803 char *original_uri = NULL;
6806 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6808 if (!original_uri) {
6809 LOGE("there is no original uri.");
6810 return MM_ERROR_PLAYER_INVALID_STATE;
6813 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6814 player->uri_info.uri_idx = 0;
6816 SECURE_LOGD("add original path at first : %s", original_uri);
6820 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6821 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6825 return MM_ERROR_NONE;
6829 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6831 mmplayer_t *player = (mmplayer_t *)hplayer;
6832 char *next_uri = NULL;
6833 guint num_of_list = 0;
6836 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6838 num_of_list = g_list_length(player->uri_info.uri_list);
6840 if (num_of_list > 0) {
6841 gint uri_idx = player->uri_info.uri_idx;
6843 if (uri_idx < num_of_list - 1)
6848 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6849 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6851 *uri = g_strdup(next_uri);
6855 return MM_ERROR_NONE;
6859 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6860 GstCaps *caps, gpointer data)
6862 mmplayer_t *player = (mmplayer_t *)data;
6863 const gchar *klass = NULL;
6864 const gchar *mime = NULL;
6865 gchar *caps_str = NULL;
6867 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6868 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6869 caps_str = gst_caps_to_string(caps);
6871 LOGW("unknown type of caps : %s from %s",
6872 caps_str, GST_ELEMENT_NAME(elem));
6874 MMPLAYER_FREEIF(caps_str);
6876 /* There is no available codec. */
6877 __mmplayer_check_not_supported_codec(player, klass, mime);
6881 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6882 GstCaps *caps, gpointer data)
6884 mmplayer_t *player = (mmplayer_t *)data;
6885 const char *mime = NULL;
6886 gboolean ret = TRUE;
6888 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6889 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6891 if (g_str_has_prefix(mime, "audio")) {
6892 GstStructure *caps_structure = NULL;
6893 gint samplerate = 0;
6895 gchar *caps_str = NULL;
6897 caps_structure = gst_caps_get_structure(caps, 0);
6898 gst_structure_get_int(caps_structure, "rate", &samplerate);
6899 gst_structure_get_int(caps_structure, "channels", &channels);
6901 if ((channels > 0 && samplerate == 0)) {
6902 LOGD("exclude audio...");
6906 caps_str = gst_caps_to_string(caps);
6907 /* set it directly because not sent by TAG */
6908 if (g_strrstr(caps_str, "mobile-xmf"))
6909 mm_player_set_attribute((MMHandleType)player, NULL,
6910 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6912 MMPLAYER_FREEIF(caps_str);
6913 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6914 LOGD("already video linked");
6917 LOGD("found new stream");
6924 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6926 gboolean ret = FALSE;
6927 GDBusConnection *conn = NULL;
6929 GVariant *result = NULL;
6930 const gchar *dbus_device_type = NULL;
6931 const gchar *dbus_ret = NULL;
6934 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6936 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6941 result = g_dbus_connection_call_sync(conn,
6942 "org.pulseaudio.Server",
6943 "/org/pulseaudio/StreamManager",
6944 "org.pulseaudio.StreamManager",
6945 "GetCurrentMediaRoutingPath",
6946 g_variant_new("(s)", "out"),
6947 G_VARIANT_TYPE("(ss)"),
6948 G_DBUS_CALL_FLAGS_NONE,
6952 if (!result || err) {
6953 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6958 /* device type is listed in stream-map.json at mmfw-sysconf */
6959 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6961 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6962 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6965 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6966 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6967 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6968 LOGD("audio offload is supportable");
6974 LOGD("audio offload is not supportable");
6977 g_variant_unref(result);
6979 g_object_unref(conn);
6984 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6986 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6987 gint64 position = 0;
6989 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6990 player->pipeline && player->pipeline->mainbin);
6992 MMPLAYER_CMD_LOCK(player);
6993 current_state = MMPLAYER_CURRENT_STATE(player);
6995 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6996 LOGW("getting current position failed in paused");
6998 _mmplayer_unrealize((MMHandleType)player);
6999 _mmplayer_realize((MMHandleType)player);
7001 _mmplayer_set_position((MMHandleType)player, position);
7003 /* async not to be blocked in streaming case */
7004 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7006 _mmplayer_pause((MMHandleType)player);
7008 if (current_state == MM_PLAYER_STATE_PLAYING)
7009 _mmplayer_start((MMHandleType)player);
7010 MMPLAYER_CMD_UNLOCK(player);
7012 LOGD("rebuilding audio pipeline is completed.");
7015 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7017 mmplayer_t *player = (mmplayer_t *)user_data;
7018 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7019 gboolean is_supportable = FALSE;
7021 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7022 LOGW("failed to get device type");
7024 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7026 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7027 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7028 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7029 LOGD("ignore this dev connected info");
7033 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7034 if (player->build_audio_offload == is_supportable) {
7035 LOGD("keep current pipeline without re-building");
7039 /* rebuild pipeline */
7040 LOGD("re-build pipeline - offload: %d", is_supportable);
7041 player->build_audio_offload = FALSE;
7042 __mmplayer_rebuild_audio_pipeline(player);
7048 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7050 unsigned int id = 0;
7052 if (player->audio_device_cb_id != 0) {
7053 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7057 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7058 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7059 LOGD("added device connected cb (%u)", id);
7060 player->audio_device_cb_id = id;
7062 LOGW("failed to add device connected cb");
7069 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7071 mmplayer_t *player = (mmplayer_t *)hplayer;
7074 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7075 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7077 *activated = player->build_audio_offload;
7079 LOGD("offload activated : %d", (int)*activated);
7082 return MM_ERROR_NONE;
7086 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7089 this function need to be updated according to the supported media format
7090 @see player->ini.audio_offload_media_format */
7092 if (__mmplayer_is_only_mp3_type(player->type)) {
7093 LOGD("offload supportable media format type");
7101 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7103 gboolean ret = FALSE;
7104 GstElementFactory *factory = NULL;
7107 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7109 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7110 if (!__mmplayer_is_offload_supported_type(player))
7113 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7114 LOGD("there is no audio offload sink");
7118 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7119 LOGW("there is no audio device type to support offload");
7123 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7125 LOGW("there is no installed audio offload sink element");
7128 gst_object_unref(factory);
7130 if (_mmplayer_acquire_hw_resource(player,
7131 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7132 LOGE("failed to acquire audio offload decoder resource");
7136 if (!__mmplayer_add_audio_device_connected_cb(player))
7139 if (!__mmplayer_is_audio_offload_device_type(player))
7142 LOGD("audio offload can be built");
7147 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7153 static GstAutoplugSelectResult
7154 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7156 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7157 int audio_offload = 0;
7159 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7160 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7162 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7163 LOGD("expose audio path to build offload output path");
7164 player->build_audio_offload = TRUE;
7165 /* update codec info */
7166 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7167 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7168 player->audiodec_linked = 1;
7170 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7174 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7175 And need to consider the multi-track audio content.
7176 There is no HW audio decoder in public. */
7178 /* set stream information */
7179 if (!player->audiodec_linked)
7180 _mmplayer_set_audio_attrs(player, caps);
7182 /* update codec info */
7183 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7184 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7185 player->audiodec_linked = 1;
7187 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7189 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7190 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7192 /* mark video decoder for acquire */
7193 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7194 LOGW("video decoder resource is already acquired, skip it.");
7195 ret = GST_AUTOPLUG_SELECT_SKIP;
7199 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7200 LOGE("failed to acquire video decoder resource");
7201 ret = GST_AUTOPLUG_SELECT_SKIP;
7204 player->interrupted_by_resource = FALSE;
7207 /* update codec info */
7208 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7209 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7210 player->videodec_linked = 1;
7218 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7219 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7221 #define DEFAULT_IDX 0xFFFF
7222 #define MIN_FACTORY_NUM 2
7223 mmplayer_t *player = (mmplayer_t *)data;
7224 GValueArray *new_factories = NULL;
7225 GValue val = { 0, };
7226 GstElementFactory *factory = NULL;
7227 const gchar *klass = NULL;
7228 gchar *factory_name = NULL;
7229 guint hw_dec_idx = DEFAULT_IDX;
7230 guint first_sw_dec_idx = DEFAULT_IDX;
7231 guint last_sw_dec_idx = DEFAULT_IDX;
7232 guint new_pos = DEFAULT_IDX;
7233 guint rm_pos = DEFAULT_IDX;
7234 int audio_codec_type;
7235 int video_codec_type;
7236 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7238 if (factories->n_values < MIN_FACTORY_NUM)
7241 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7242 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7245 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7247 for (int i = 0 ; i < factories->n_values ; i++) {
7248 gchar *hw_dec_info = NULL;
7249 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7251 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7253 LOGW("failed to get factory object");
7256 klass = gst_element_factory_get_klass(factory);
7257 factory_name = GST_OBJECT_NAME(factory);
7260 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7262 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7263 if (!player->need_audio_dec_sorting) {
7264 LOGD("sorting is not required");
7267 codec_type = audio_codec_type;
7268 hw_dec_info = player->ini.audiocodec_element_hw;
7269 sw_dec_info = player->ini.audiocodec_element_sw;
7270 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7271 if (!player->need_video_dec_sorting) {
7272 LOGD("sorting is not required");
7275 codec_type = video_codec_type;
7276 hw_dec_info = player->ini.videocodec_element_hw;
7277 sw_dec_info = player->ini.videocodec_element_sw;
7282 if (g_strrstr(factory_name, hw_dec_info)) {
7285 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7286 if (strstr(factory_name, sw_dec_info[j])) {
7287 last_sw_dec_idx = i;
7288 if (first_sw_dec_idx == DEFAULT_IDX) {
7289 first_sw_dec_idx = i;
7294 if (first_sw_dec_idx == DEFAULT_IDX)
7295 LOGW("unknown codec %s", factory_name);
7299 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7302 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7303 if (hw_dec_idx < first_sw_dec_idx)
7305 new_pos = first_sw_dec_idx;
7306 rm_pos = hw_dec_idx + 1;
7307 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7308 if (last_sw_dec_idx < hw_dec_idx)
7310 new_pos = last_sw_dec_idx + 1;
7311 rm_pos = hw_dec_idx;
7316 /* change position - insert H/W decoder according to the new position */
7317 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7319 LOGW("failed to get factory object");
7322 new_factories = g_value_array_copy(factories);
7323 g_value_init (&val, G_TYPE_OBJECT);
7324 g_value_set_object (&val, factory);
7325 g_value_array_insert(new_factories, new_pos, &val);
7326 g_value_unset (&val);
7327 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7329 for (int i = 0 ; i < new_factories->n_values ; i++) {
7330 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7332 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7333 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7335 LOGE("[Re-arranged] failed to get factory object");
7338 return new_factories;
7342 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7343 GstCaps *caps, GstElementFactory *factory, gpointer data)
7345 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7346 mmplayer_t *player = (mmplayer_t *)data;
7348 gchar *factory_name = NULL;
7349 gchar *caps_str = NULL;
7350 const gchar *klass = NULL;
7353 factory_name = GST_OBJECT_NAME(factory);
7354 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7355 caps_str = gst_caps_to_string(caps);
7357 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7359 /* store type string */
7360 if (player->type == NULL) {
7361 player->type = gst_caps_to_string(caps);
7362 __mmplayer_update_content_type_info(player);
7365 /* filtering exclude keyword */
7366 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7367 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7368 LOGW("skipping [%s] by exculde keyword [%s]",
7369 factory_name, player->ini.exclude_element_keyword[idx]);
7371 result = GST_AUTOPLUG_SELECT_SKIP;
7376 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7377 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7378 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7379 factory_name, player->ini.unsupported_codec_keyword[idx]);
7380 result = GST_AUTOPLUG_SELECT_SKIP;
7385 /* exclude webm format */
7386 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7387 * because webm format is not supportable.
7388 * If webm is disabled in "autoplug-continue", there is no state change
7389 * failure or error because the decodebin will expose the pad directly.
7390 * It make MSL invoke _prepare_async_callback.
7391 * So, we need to disable webm format in "autoplug-select" */
7392 if (caps_str && strstr(caps_str, "webm")) {
7393 LOGW("webm is not supported");
7394 result = GST_AUTOPLUG_SELECT_SKIP;
7398 /* check factory class for filtering */
7399 /* NOTE : msl don't need to use image plugins.
7400 * So, those plugins should be skipped for error handling.
7402 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7403 LOGD("skipping [%s] by not required", factory_name);
7404 result = GST_AUTOPLUG_SELECT_SKIP;
7408 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7409 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7410 // TO CHECK : subtitle if needed, add subparse exception.
7411 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7412 result = GST_AUTOPLUG_SELECT_SKIP;
7416 if (g_strrstr(factory_name, "mpegpsdemux")) {
7417 LOGD("skipping PS container - not support");
7418 result = GST_AUTOPLUG_SELECT_SKIP;
7422 if (g_strrstr(factory_name, "mssdemux"))
7423 player->smooth_streaming = TRUE;
7425 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7426 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7429 GstStructure *str = NULL;
7430 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7432 /* don't make video because of not required */
7433 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7434 (!player->set_mode.video_export)) {
7435 LOGD("no need video decoding, expose pad");
7436 result = GST_AUTOPLUG_SELECT_EXPOSE;
7440 /* get w/h for omx state-tune */
7441 /* FIXME: deprecated? */
7442 str = gst_caps_get_structure(caps, 0);
7443 gst_structure_get_int(str, "width", &width);
7446 if (player->v_stream_caps) {
7447 gst_caps_unref(player->v_stream_caps);
7448 player->v_stream_caps = NULL;
7451 player->v_stream_caps = gst_caps_copy(caps);
7452 LOGD("take caps for video state tune");
7453 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7457 if (g_strrstr(klass, "Codec/Decoder")) {
7458 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7459 if (result != GST_AUTOPLUG_SELECT_TRY) {
7460 LOGW("skip add decoder");
7466 MMPLAYER_FREEIF(caps_str);
7472 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7475 //mmplayer_t *player = (mmplayer_t *)data;
7476 GstCaps *caps = NULL;
7478 LOGD("[Decodebin2] pad-removed signal");
7480 caps = gst_pad_query_caps(new_pad, NULL);
7482 LOGW("query caps is NULL");
7486 gchar *caps_str = NULL;
7487 caps_str = gst_caps_to_string(caps);
7489 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7491 MMPLAYER_FREEIF(caps_str);
7492 gst_caps_unref(caps);
7496 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7498 mmplayer_t *player = (mmplayer_t *)data;
7501 MMPLAYER_RETURN_IF_FAIL(player);
7503 LOGD("got about to finish signal");
7505 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7506 LOGW("Fail to get cmd lock");
7510 if (!__mmplayer_verify_gapless_play_path(player)) {
7511 LOGD("decoding is finished.");
7512 MMPLAYER_CMD_UNLOCK(player);
7516 _mmplayer_set_reconfigure_state(player, TRUE);
7517 MMPLAYER_CMD_UNLOCK(player);
7519 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL);
7520 __mmplayer_deactivate_old_path(player);
7526 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7528 mmplayer_t *player = (mmplayer_t *)data;
7529 GstIterator *iter = NULL;
7530 GValue item = { 0, };
7532 gboolean done = FALSE;
7533 gboolean is_all_drained = TRUE;
7536 MMPLAYER_RETURN_IF_FAIL(player);
7538 LOGD("got drained signal");
7540 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7541 LOGW("Fail to get cmd lock");
7545 if (!__mmplayer_verify_gapless_play_path(player)) {
7546 LOGD("decoding is finished.");
7547 MMPLAYER_CMD_UNLOCK(player);
7551 _mmplayer_set_reconfigure_state(player, TRUE);
7552 MMPLAYER_CMD_UNLOCK(player);
7554 /* check decodebin src pads whether they received EOS or not */
7555 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7558 switch (gst_iterator_next(iter, &item)) {
7559 case GST_ITERATOR_OK:
7560 pad = g_value_get_object(&item);
7561 if (pad && !GST_PAD_IS_EOS(pad)) {
7562 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7563 is_all_drained = FALSE;
7566 g_value_reset(&item);
7568 case GST_ITERATOR_RESYNC:
7569 gst_iterator_resync(iter);
7571 case GST_ITERATOR_ERROR:
7572 case GST_ITERATOR_DONE:
7577 g_value_unset(&item);
7578 gst_iterator_free(iter);
7580 if (!is_all_drained) {
7581 LOGD("Wait util the all pads get EOS.");
7586 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7587 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7589 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7590 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7591 __mmplayer_deactivate_old_path(player);
7597 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7599 mmplayer_t *player = (mmplayer_t *)data;
7600 const gchar *klass = NULL;
7601 gchar *factory_name = NULL;
7603 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7604 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7606 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7608 if (__mmplayer_add_dump_buffer_probe(player, element))
7609 LOGD("add buffer probe");
7611 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7612 gchar *selected = NULL;
7613 selected = g_strdup(GST_ELEMENT_NAME(element));
7614 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7616 /* update codec info */
7617 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7618 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7619 player->audiodec_linked = 1;
7620 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7621 /* update codec info */
7622 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7623 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7624 player->videodec_linked = 1;
7627 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7628 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7629 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7631 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7632 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7634 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7635 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7636 "max-video-width", player->adaptive_info.limit.width,
7637 "max-video-height", player->adaptive_info.limit.height, NULL);
7639 } else if (g_strrstr(klass, "Demuxer")) {
7641 LOGD("plugged element is demuxer. take it");
7643 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7644 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7647 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7648 int surface_type = 0;
7650 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7653 // to support trust-zone only
7654 if (g_strrstr(factory_name, "asfdemux")) {
7655 LOGD("set file-location %s", player->profile.uri);
7656 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7657 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7658 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7659 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7660 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7661 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7662 (__mmplayer_is_only_mp3_type(player->type))) {
7663 LOGD("[mpegaudioparse] set streaming pull mode.");
7664 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7666 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7667 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7670 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7671 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7672 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7674 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7675 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7677 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7678 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7679 (MMPLAYER_IS_DASH_STREAMING(player))) {
7680 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7681 _mm_player_streaming_set_multiqueue(player->streamer, element);
7682 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7691 __mmplayer_release_misc(mmplayer_t *player)
7694 bool cur_mode = player->set_mode.rich_audio;
7697 MMPLAYER_RETURN_IF_FAIL(player);
7699 player->sent_bos = FALSE;
7700 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7702 player->seek_state = MMPLAYER_SEEK_NONE;
7704 player->total_bitrate = 0;
7705 player->total_maximum_bitrate = 0;
7707 player->not_found_demuxer = 0;
7709 player->last_position = 0;
7710 player->duration = 0;
7711 player->http_content_size = 0;
7712 player->not_supported_codec = MISSING_PLUGIN_NONE;
7713 player->can_support_codec = FOUND_PLUGIN_NONE;
7714 player->pending_seek.is_pending = false;
7715 player->pending_seek.pos = 0;
7716 player->msg_posted = FALSE;
7717 player->has_many_types = FALSE;
7718 player->is_subtitle_force_drop = FALSE;
7719 player->play_subtitle = FALSE;
7720 player->adjust_subtitle_pos = 0;
7721 player->has_closed_caption = FALSE;
7722 player->set_mode.video_export = false;
7723 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7724 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7726 player->set_mode.rich_audio = cur_mode;
7728 if (player->audio_device_cb_id > 0 &&
7729 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7730 LOGW("failed to remove audio device_connected_callback");
7731 player->audio_device_cb_id = 0;
7733 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7734 player->bitrate[i] = 0;
7735 player->maximum_bitrate[i] = 0;
7738 /* free memory related to audio effect */
7739 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7741 if (player->adaptive_info.var_list) {
7742 g_list_free_full(player->adaptive_info.var_list, g_free);
7743 player->adaptive_info.var_list = NULL;
7746 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7747 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7748 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7750 /* Reset video360 settings to their defaults in case if the pipeline is to be
7753 player->video360_metadata.is_spherical = -1;
7754 player->is_openal_plugin_used = FALSE;
7756 player->is_content_spherical = FALSE;
7757 player->is_video360_enabled = TRUE;
7758 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7759 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7760 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7761 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7762 player->video360_zoom = 1.0f;
7763 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7764 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7766 player->sound.rg_enable = false;
7768 __mmplayer_initialize_video_roi(player);
7773 __mmplayer_release_misc_post(mmplayer_t *player)
7775 char *original_uri = NULL;
7778 /* player->pipeline is already released before. */
7779 MMPLAYER_RETURN_IF_FAIL(player);
7781 player->video_decoded_cb = NULL;
7782 player->video_decoded_cb_user_param = NULL;
7783 player->video_stream_prerolled = false;
7785 player->audio_decoded_cb = NULL;
7786 player->audio_decoded_cb_user_param = NULL;
7787 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7789 player->audio_stream_changed_cb = NULL;
7790 player->audio_stream_changed_cb_user_param = NULL;
7792 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7794 /* clean found audio decoders */
7795 if (player->audio_decoders) {
7796 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7797 player->audio_decoders = NULL;
7800 /* clean the uri list except original uri */
7801 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7803 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7804 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7805 g_list_free_full(tmp, (GDestroyNotify)g_free);
7808 LOGW("failed to get original uri info");
7810 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7811 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7815 /* clear the audio stream buffer list */
7816 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7818 /* clear the video stream bo list */
7819 __mmplayer_video_stream_destroy_bo_list(player);
7820 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7822 if (player->profile.input_mem.buf) {
7823 free(player->profile.input_mem.buf);
7824 player->profile.input_mem.buf = NULL;
7826 player->profile.input_mem.len = 0;
7827 player->profile.input_mem.offset = 0;
7829 player->uri_info.uri_idx = 0;
7834 __mmplayer_check_subtitle(mmplayer_t *player)
7836 MMHandleType attrs = 0;
7837 char *subtitle_uri = NULL;
7841 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7843 /* get subtitle attribute */
7844 attrs = MMPLAYER_GET_ATTRS(player);
7848 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7849 if (!subtitle_uri || !strlen(subtitle_uri))
7852 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7853 player->is_external_subtitle_present = TRUE;
7861 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7863 MMPLAYER_RETURN_IF_FAIL(player);
7865 if (player->eos_timer) {
7866 LOGD("cancel eos timer");
7867 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7868 player->eos_timer = 0;
7875 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7879 MMPLAYER_RETURN_IF_FAIL(player);
7880 MMPLAYER_RETURN_IF_FAIL(sink);
7882 player->sink_elements = g_list_append(player->sink_elements, sink);
7888 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7892 MMPLAYER_RETURN_IF_FAIL(player);
7893 MMPLAYER_RETURN_IF_FAIL(sink);
7895 player->sink_elements = g_list_remove(player->sink_elements, sink);
7901 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7902 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7904 mmplayer_signal_item_t *item = NULL;
7907 MMPLAYER_RETURN_IF_FAIL(player);
7909 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7910 LOGE("invalid signal type [%d]", type);
7914 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7916 LOGE("cannot connect signal [%s]", signal);
7921 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7922 player->signals[type] = g_list_append(player->signals[type], item);
7928 /* NOTE : be careful with calling this api. please refer to below glib comment
7929 * glib comment : Note that there is a bug in GObject that makes this function much
7930 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7931 * will no longer be called, but, the signal handler is not currently disconnected.
7932 * If the instance is itself being freed at the same time than this doesn't matter,
7933 * since the signal will automatically be removed, but if instance persists,
7934 * then the signal handler will leak. You should not remove the signal yourself
7935 * because in a future versions of GObject, the handler will automatically be
7938 * It's possible to work around this problem in a way that will continue to work
7939 * with future versions of GObject by checking that the signal handler is still
7940 * connected before disconnected it:
7942 * if (g_signal_handler_is_connected(instance, id))
7943 * g_signal_handler_disconnect(instance, id);
7946 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7948 GList *sig_list = NULL;
7949 mmplayer_signal_item_t *item = NULL;
7953 MMPLAYER_RETURN_IF_FAIL(player);
7955 LOGD("release signals type : %d", type);
7957 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7958 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7959 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7960 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7961 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7962 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7966 sig_list = player->signals[type];
7968 for (; sig_list; sig_list = sig_list->next) {
7969 item = sig_list->data;
7971 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7972 if (g_signal_handler_is_connected(item->obj, item->sig))
7973 g_signal_handler_disconnect(item->obj, item->sig);
7976 MMPLAYER_FREEIF(item);
7979 g_list_free(player->signals[type]);
7980 player->signals[type] = NULL;
7988 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7990 mmplayer_t *player = 0;
7991 int prev_display_surface_type = 0;
7995 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7997 player = MM_PLAYER_CAST(handle);
7999 /* check video sinkbin is created */
8000 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8001 LOGW("Videosink is already created");
8002 return MM_ERROR_NONE;
8005 LOGD("videosink element is not yet ready");
8007 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8008 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8010 return MM_ERROR_INVALID_ARGUMENT;
8013 /* load previous attributes */
8014 if (player->attrs) {
8015 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8016 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8017 if (prev_display_surface_type == surface_type) {
8018 LOGD("incoming display surface type is same as previous one, do nothing..");
8020 return MM_ERROR_NONE;
8023 LOGE("failed to load attributes");
8025 return MM_ERROR_PLAYER_INTERNAL;
8028 /* videobin is not created yet, so we just set attributes related to display surface */
8029 LOGD("store display attribute for given surface type(%d)", surface_type);
8030 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8031 "display_overlay", wl_surface_id, NULL);
8034 return MM_ERROR_NONE;
8037 /* Note : if silent is true, then subtitle would not be displayed. :*/
8039 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8041 mmplayer_t *player = (mmplayer_t *)hplayer;
8045 /* check player handle */
8046 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8048 player->set_mode.subtitle_off = silent;
8050 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8054 return MM_ERROR_NONE;
8058 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8060 mmplayer_gst_element_t *mainbin = NULL;
8061 mmplayer_gst_element_t *textbin = NULL;
8062 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8063 GstState current_state = GST_STATE_VOID_PENDING;
8064 GstState element_state = GST_STATE_VOID_PENDING;
8065 GstState element_pending_state = GST_STATE_VOID_PENDING;
8067 GstEvent *event = NULL;
8068 int result = MM_ERROR_NONE;
8070 GstClock *curr_clock = NULL;
8071 GstClockTime base_time, start_time, curr_time;
8076 /* check player handle */
8077 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8079 player->pipeline->mainbin &&
8080 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8082 mainbin = player->pipeline->mainbin;
8083 textbin = player->pipeline->textbin;
8085 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8087 // sync clock with current pipeline
8088 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8089 curr_time = gst_clock_get_time(curr_clock);
8091 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8092 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8094 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8095 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8097 if (current_state > GST_STATE_READY) {
8098 // sync state with current pipeline
8099 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8100 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8101 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8103 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8104 if (GST_STATE_CHANGE_FAILURE == ret) {
8105 LOGE("fail to state change.");
8106 result = MM_ERROR_PLAYER_INTERNAL;
8110 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8111 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8114 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8115 gst_object_unref(curr_clock);
8118 // seek to current position
8119 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8120 result = MM_ERROR_PLAYER_INVALID_STATE;
8121 LOGE("gst_element_query_position failed, invalid state");
8125 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8126 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);
8128 _mmplayer_gst_send_event_to_sink(player, event);
8130 result = MM_ERROR_PLAYER_INTERNAL;
8131 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8135 /* sync state with current pipeline */
8136 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8137 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8138 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8140 return MM_ERROR_NONE;
8143 /* release text pipeline resource */
8144 player->textsink_linked = 0;
8146 /* release signal */
8147 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8149 /* release textbin with it's childs */
8150 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8151 MMPLAYER_FREEIF(player->pipeline->textbin);
8152 player->pipeline->textbin = NULL;
8154 /* release subtitle elem */
8155 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8156 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8162 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8164 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8165 GstState current_state = GST_STATE_VOID_PENDING;
8167 MMHandleType attrs = 0;
8168 mmplayer_gst_element_t *mainbin = NULL;
8169 mmplayer_gst_element_t *textbin = NULL;
8171 gchar *subtitle_uri = NULL;
8172 int result = MM_ERROR_NONE;
8173 const gchar *charset = NULL;
8177 /* check player handle */
8178 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8180 player->pipeline->mainbin &&
8181 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8182 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8184 mainbin = player->pipeline->mainbin;
8185 textbin = player->pipeline->textbin;
8187 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8188 if (current_state < GST_STATE_READY) {
8189 result = MM_ERROR_PLAYER_INVALID_STATE;
8190 LOGE("Pipeline is not in proper state");
8194 attrs = MMPLAYER_GET_ATTRS(player);
8196 LOGE("cannot get content attribute");
8197 result = MM_ERROR_PLAYER_INTERNAL;
8201 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8202 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8203 LOGE("subtitle uri is not proper filepath");
8204 result = MM_ERROR_PLAYER_INVALID_URI;
8208 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8209 LOGE("failed to get storage info of subtitle path");
8210 result = MM_ERROR_PLAYER_INVALID_URI;
8214 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8215 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8217 if (!strcmp(filepath, subtitle_uri)) {
8218 LOGD("subtitle path is not changed");
8221 if (mm_player_set_attribute((MMHandleType)player, NULL,
8222 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8223 LOGE("failed to set attribute");
8228 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8229 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8230 player->subtitle_language_list = NULL;
8231 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8233 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8234 if (ret != GST_STATE_CHANGE_SUCCESS) {
8235 LOGE("failed to change state of textbin to READY");
8236 result = MM_ERROR_PLAYER_INTERNAL;
8240 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8241 if (ret != GST_STATE_CHANGE_SUCCESS) {
8242 LOGE("failed to change state of subparse to READY");
8243 result = MM_ERROR_PLAYER_INTERNAL;
8247 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8248 if (ret != GST_STATE_CHANGE_SUCCESS) {
8249 LOGE("failed to change state of filesrc to READY");
8250 result = MM_ERROR_PLAYER_INTERNAL;
8254 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8256 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8258 charset = _mmplayer_get_charset(filepath);
8260 LOGD("detected charset is %s", charset);
8261 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8264 result = _mmplayer_sync_subtitle_pipeline(player);
8271 /* API to switch between external subtitles */
8273 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8275 int result = MM_ERROR_NONE;
8276 mmplayer_t *player = (mmplayer_t *)hplayer;
8281 /* check player handle */
8282 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8284 /* filepath can be null in idle state */
8286 /* check file path */
8287 if ((path = strstr(filepath, "file://")))
8288 result = _mmplayer_exist_file_path(path + 7);
8290 result = _mmplayer_exist_file_path(filepath);
8292 if (result != MM_ERROR_NONE) {
8293 LOGE("invalid subtitle path 0x%X", result);
8294 return result; /* file not found or permission denied */
8298 if (!player->pipeline) {
8300 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8301 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8302 LOGE("failed to set attribute");
8303 return MM_ERROR_PLAYER_INTERNAL;
8306 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8307 /* check filepath */
8308 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8310 if (!__mmplayer_check_subtitle(player)) {
8311 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8312 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8313 LOGE("failed to set attribute");
8314 return MM_ERROR_PLAYER_INTERNAL;
8317 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8318 LOGE("fail to create text pipeline");
8319 return MM_ERROR_PLAYER_INTERNAL;
8322 result = _mmplayer_sync_subtitle_pipeline(player);
8324 result = __mmplayer_change_external_subtitle_language(player, filepath);
8327 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8328 player->is_external_subtitle_added_now = TRUE;
8330 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8331 if (!player->subtitle_language_list) {
8332 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8333 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8334 LOGW("subtitle language list is not updated yet");
8336 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8344 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8346 guint active_idx = 0;
8347 GstStream *stream = NULL;
8348 GList *streams = NULL;
8349 GstEvent *ev = NULL;
8350 GstCaps *caps = NULL;
8352 LOGD("Switching Streams... type: %d, index: %d", type, index);
8354 player->track[type].active_track_index = index;
8356 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8357 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8358 if (player->track[i].total_track_num > 0) {
8359 active_idx = player->track[i].active_track_index;
8360 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8361 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8362 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8364 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8365 caps = gst_stream_get_caps(stream);
8367 _mmplayer_set_audio_attrs(player, caps);
8368 gst_caps_unref(caps);
8374 ev = gst_event_new_select_streams(streams);
8375 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, ev);
8376 g_list_free(streams);
8378 return MM_ERROR_NONE;
8382 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8384 int result = MM_ERROR_NONE;
8385 gchar *change_pad_name = NULL;
8386 GstPad *sinkpad = NULL;
8387 mmplayer_gst_element_t *mainbin = NULL;
8388 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8389 GstCaps *caps = NULL;
8390 gint total_track_num = 0;
8394 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8395 MM_ERROR_PLAYER_NOT_INITIALIZED);
8397 LOGD("Change Track(%d) to %d", type, index);
8399 mainbin = player->pipeline->mainbin;
8401 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8402 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8403 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8404 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8406 /* Changing Video Track is not supported. */
8407 LOGE("Track Type Error");
8411 if (mainbin[elem_idx].gst == NULL) {
8412 result = MM_ERROR_PLAYER_NO_OP;
8413 LOGD("Req track doesn't exist");
8417 total_track_num = player->track[type].total_track_num;
8418 if (total_track_num <= 0) {
8419 result = MM_ERROR_PLAYER_NO_OP;
8420 LOGD("Language list is not available");
8424 if ((index < 0) || (index >= total_track_num)) {
8425 result = MM_ERROR_INVALID_ARGUMENT;
8426 LOGD("Not a proper index : %d", index);
8430 /*To get the new pad from the selector*/
8431 change_pad_name = g_strdup_printf("sink_%u", index);
8432 if (change_pad_name == NULL) {
8433 result = MM_ERROR_PLAYER_INTERNAL;
8434 LOGD("Pad does not exists");
8438 LOGD("new active pad name: %s", change_pad_name);
8440 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8441 if (sinkpad == NULL) {
8442 LOGD("sinkpad is NULL");
8443 result = MM_ERROR_PLAYER_INTERNAL;
8447 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8448 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8450 caps = gst_pad_get_current_caps(sinkpad);
8451 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8454 gst_object_unref(sinkpad);
8456 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8457 _mmplayer_set_audio_attrs(player, caps);
8460 gst_caps_unref(caps);
8463 MMPLAYER_FREEIF(change_pad_name);
8468 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8470 int result = MM_ERROR_NONE;
8471 mmplayer_t *player = NULL;
8472 mmplayer_gst_element_t *mainbin = NULL;
8474 gint current_active_index = 0;
8476 GstState current_state = GST_STATE_VOID_PENDING;
8481 player = (mmplayer_t *)hplayer;
8482 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8484 if (!player->pipeline) {
8485 LOGE("Track %d pre setting -> %d", type, index);
8487 player->track[type].active_track_index = index;
8491 mainbin = player->pipeline->mainbin;
8493 current_active_index = player->track[type].active_track_index;
8495 /*If index is same as running index no need to change the pad*/
8496 if (current_active_index == index)
8499 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8500 result = MM_ERROR_PLAYER_INVALID_STATE;
8504 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8505 if (current_state < GST_STATE_PAUSED) {
8506 result = MM_ERROR_PLAYER_INVALID_STATE;
8507 LOGW("Pipeline not in porper state");
8511 if (MMPLAYER_USE_DECODEBIN(player))
8512 result = __mmplayer_change_selector_pad(player, type, index);
8514 result = __mmplayer_switch_stream(player, type, index);
8516 if (result != MM_ERROR_NONE) {
8517 LOGE("failed to change track");
8521 player->track[type].active_track_index = index;
8523 if (MMPLAYER_USE_DECODEBIN(player)) {
8524 GstEvent *event = NULL;
8525 if (current_state == GST_STATE_PLAYING) {
8526 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8527 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8528 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8530 _mmplayer_gst_send_event_to_sink(player, event);
8532 result = MM_ERROR_PLAYER_INTERNAL;
8543 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8545 mmplayer_t *player = (mmplayer_t *)hplayer;
8549 /* check player handle */
8550 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8552 *silent = player->set_mode.subtitle_off;
8554 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8558 return MM_ERROR_NONE;
8562 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8564 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8565 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8567 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8568 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8572 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8573 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8574 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8575 mmplayer_dump_t *dump_s;
8576 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8577 if (dump_s == NULL) {
8578 LOGE("malloc fail");
8582 dump_s->dump_element_file = NULL;
8583 dump_s->dump_pad = NULL;
8584 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8586 if (dump_s->dump_pad) {
8587 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8588 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]);
8589 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8590 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);
8591 /* add list for removed buffer probe and close FILE */
8592 player->dump_list = g_list_append(player->dump_list, dump_s);
8593 LOGD("%s sink pad added buffer probe for dump", factory_name);
8596 MMPLAYER_FREEIF(dump_s);
8597 LOGE("failed to get %s sink pad added", factory_name);
8604 static GstPadProbeReturn
8605 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8607 FILE *dump_data = (FILE *)u_data;
8609 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8610 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8612 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8614 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8616 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8618 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8620 gst_buffer_unmap(buffer, &probe_info);
8622 return GST_PAD_PROBE_OK;
8626 __mmplayer_release_dump_list(GList *dump_list)
8628 GList *d_list = dump_list;
8633 for (; d_list; d_list = g_list_next(d_list)) {
8634 mmplayer_dump_t *dump_s = d_list->data;
8635 if (dump_s->dump_pad) {
8636 if (dump_s->probe_handle_id)
8637 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8638 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8640 if (dump_s->dump_element_file) {
8641 fclose(dump_s->dump_element_file);
8642 dump_s->dump_element_file = NULL;
8644 MMPLAYER_FREEIF(dump_s);
8646 g_list_free(dump_list);
8651 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8653 mmplayer_t *player = (mmplayer_t *)hplayer;
8657 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8658 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8660 *exist = (bool)player->has_closed_caption;
8664 return MM_ERROR_NONE;
8668 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8673 LOGD("unref internal gst buffer %p", buffer);
8675 gst_buffer_unref((GstBuffer *)buffer);
8682 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8684 mmplayer_t *player = (mmplayer_t *)hplayer;
8688 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8689 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8691 if (MMPLAYER_IS_STREAMING(player))
8692 *timeout = (int)player->ini.live_state_change_timeout;
8694 *timeout = (int)player->ini.localplayback_state_change_timeout;
8696 LOGD("timeout = %d", *timeout);
8699 return MM_ERROR_NONE;
8703 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8707 MMPLAYER_RETURN_IF_FAIL(player);
8709 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8711 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8712 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8713 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8714 player->storage_info[i].id = -1;
8715 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8717 if (path_type != MMPLAYER_PATH_MAX)
8726 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8728 int ret = MM_ERROR_NONE;
8729 mmplayer_t *player = (mmplayer_t *)hplayer;
8730 MMMessageParamType msg_param = {0, };
8733 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8735 LOGW("state changed storage %d:%d", id, state);
8737 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8738 return MM_ERROR_NONE;
8740 /* FIXME: text path should be handled seperately. */
8741 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8742 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8743 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8744 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8745 LOGW("external storage is removed");
8747 if (player->msg_posted == FALSE) {
8748 memset(&msg_param, 0, sizeof(MMMessageParamType));
8749 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8750 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8751 player->msg_posted = TRUE;
8754 /* unrealize the player */
8755 ret = _mmplayer_unrealize(hplayer);
8756 if (ret != MM_ERROR_NONE)
8757 LOGE("failed to unrealize");
8765 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8767 int ret = MM_ERROR_NONE;
8768 mmplayer_t *player = (mmplayer_t *)hplayer;
8769 int idx = 0, total = 0;
8770 gchar *result = NULL, *tmp = NULL;
8773 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8774 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8776 total = *num = g_list_length(player->adaptive_info.var_list);
8778 LOGW("There is no stream variant info.");
8782 result = g_strdup("");
8783 for (idx = 0 ; idx < total ; idx++) {
8784 stream_variant_t *v_data = NULL;
8785 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8788 gchar data[64] = {0};
8789 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8791 tmp = g_strconcat(result, data, NULL);
8795 LOGW("There is no variant data in %d", idx);
8800 *var_info = (char *)result;
8802 LOGD("variant info %d:%s", *num, *var_info);
8808 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8810 int ret = MM_ERROR_NONE;
8811 mmplayer_t *player = (mmplayer_t *)hplayer;
8814 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8816 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8818 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8819 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8820 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8822 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8823 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8824 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8825 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8827 /* FIXME: seek to current position for applying new variant limitation */
8836 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8838 int ret = MM_ERROR_NONE;
8839 mmplayer_t *player = (mmplayer_t *)hplayer;
8842 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8843 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8845 *bandwidth = player->adaptive_info.limit.bandwidth;
8846 *width = player->adaptive_info.limit.width;
8847 *height = player->adaptive_info.limit.height;
8849 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8856 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8858 int ret = MM_ERROR_NONE;
8859 mmplayer_t *player = (mmplayer_t *)hplayer;
8862 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8863 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8864 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8866 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8868 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8869 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8870 else /* live case */
8871 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8873 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8880 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8882 #define IDX_FIRST_SW_CODEC 0
8883 mmplayer_t *player = (mmplayer_t *)hplayer;
8884 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8885 const char *attr_name = NULL;
8886 const char *default_type = NULL;
8887 const char *element_hw = NULL;
8888 const char *element_sw = NULL;
8891 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8893 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
8895 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
8896 switch (stream_type) {
8897 case MM_PLAYER_STREAM_TYPE_AUDIO:
8898 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
8899 default_type = player->ini.audiocodec_default_type;
8900 element_hw = player->ini.audiocodec_element_hw;
8901 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
8903 case MM_PLAYER_STREAM_TYPE_VIDEO:
8904 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
8905 default_type = player->ini.videocodec_default_type;
8906 element_hw = player->ini.videocodec_element_hw;
8907 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
8910 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8911 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8915 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
8917 if (!strcmp(default_type, "sw"))
8918 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
8920 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
8922 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
8923 codec_type = default_codec_type;
8925 /* to support codec selection, codec info have to be added in ini file.
8926 in case of hw codec is selected, filter elements should be applied
8927 depending on the hw capabilities. */
8928 if (codec_type != default_codec_type) {
8929 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
8930 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
8931 LOGE("There is no codec for type %d", codec_type);
8932 return MM_ERROR_PLAYER_NO_OP;
8935 LOGD("sorting is required");
8936 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
8937 player->need_audio_dec_sorting = TRUE;
8939 player->need_video_dec_sorting = TRUE;
8942 LOGD("update %s codec_type to %d", attr_name, codec_type);
8943 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8946 return MM_ERROR_NONE;
8950 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8952 mmplayer_t *player = (mmplayer_t *)hplayer;
8953 GstElement *rg_vol_element = NULL;
8957 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8959 player->sound.rg_enable = enabled;
8961 /* just hold rgvolume enable value if pipeline is not ready */
8962 if (!player->pipeline || !player->pipeline->audiobin) {
8963 LOGD("pipeline is not ready. holding rgvolume enable value");
8964 return MM_ERROR_NONE;
8967 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8969 if (!rg_vol_element) {
8970 LOGD("rgvolume element is not created");
8971 return MM_ERROR_PLAYER_INTERNAL;
8975 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8977 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8981 return MM_ERROR_NONE;
8985 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8987 mmplayer_t *player = (mmplayer_t *)hplayer;
8988 GstElement *rg_vol_element = NULL;
8989 gboolean enable = FALSE;
8993 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8994 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8996 /* just hold enable_rg value if pipeline is not ready */
8997 if (!player->pipeline || !player->pipeline->audiobin) {
8998 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8999 *enabled = player->sound.rg_enable;
9000 return MM_ERROR_NONE;
9003 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9005 if (!rg_vol_element) {
9006 LOGD("rgvolume element is not created");
9007 return MM_ERROR_PLAYER_INTERNAL;
9010 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9011 *enabled = (bool)enable;
9015 return MM_ERROR_NONE;
9019 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9021 mmplayer_t *player = (mmplayer_t *)hplayer;
9022 MMHandleType attrs = 0;
9024 int ret = MM_ERROR_NONE;
9028 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9030 attrs = MMPLAYER_GET_ATTRS(player);
9031 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9033 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9035 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9036 return MM_ERROR_PLAYER_INTERNAL;
9039 player->video_roi.scale_x = scale_x;
9040 player->video_roi.scale_y = scale_y;
9041 player->video_roi.scale_width = scale_width;
9042 player->video_roi.scale_height = scale_height;
9044 /* check video sinkbin is created */
9045 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9046 return MM_ERROR_NONE;
9048 if (!gst_video_overlay_set_video_roi_area(
9049 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9050 scale_x, scale_y, scale_width, scale_height))
9051 ret = MM_ERROR_PLAYER_INTERNAL;
9053 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9054 scale_x, scale_y, scale_width, scale_height);
9062 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9064 mmplayer_t *player = (mmplayer_t *)hplayer;
9065 int ret = MM_ERROR_NONE;
9069 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9070 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9072 *scale_x = player->video_roi.scale_x;
9073 *scale_y = player->video_roi.scale_y;
9074 *scale_width = player->video_roi.scale_width;
9075 *scale_height = player->video_roi.scale_height;
9077 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9078 *scale_x, *scale_y, *scale_width, *scale_height);
9084 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9086 mmplayer_t *player = (mmplayer_t *)hplayer;
9090 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9092 player->client_pid = pid;
9094 LOGD("client pid[%d] %p", pid, player);
9098 return MM_ERROR_NONE;
9102 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9104 mmplayer_t *player = (mmplayer_t *)hplayer;
9105 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9106 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9110 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9111 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9114 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9116 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9118 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9119 return MM_ERROR_NONE;
9121 /* in case of audio codec default type is HW */
9123 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9124 if (player->ini.support_audio_effect)
9125 return MM_ERROR_NONE;
9126 elem_id = MMPLAYER_A_FILTER;
9128 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9129 if (player->ini.support_replaygain_control)
9130 return MM_ERROR_NONE;
9131 elem_id = MMPLAYER_A_RGVOL;
9133 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9134 if (player->ini.support_pitch_control)
9135 return MM_ERROR_NONE;
9136 elem_id = MMPLAYER_A_PITCH;
9138 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9139 if (player->ini.support_audio_effect)
9140 return MM_ERROR_NONE;
9142 /* default case handling is not required */
9145 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9146 LOGW("audio control option [%d] is not available", opt);
9149 /* setting pcm exporting option is allowed before READY state */
9150 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9151 return MM_ERROR_PLAYER_INVALID_STATE;
9153 /* check whether the audio filter exist or not after READY state,
9154 because the sw codec could be added during auto-plugging in some cases */
9155 if (!player->pipeline ||
9156 !player->pipeline->audiobin ||
9157 !player->pipeline->audiobin[elem_id].gst) {
9158 LOGW("there is no audio elem [%d]", elem_id);
9163 LOGD("audio control opt %d, available %d", opt, *available);
9167 return MM_ERROR_NONE;
9171 __mmplayer_update_duration_value(mmplayer_t *player)
9173 gboolean ret = FALSE;
9174 gint64 dur_nsec = 0;
9175 LOGD("try to update duration");
9177 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9178 player->duration = dur_nsec;
9179 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9183 if (player->duration < 0) {
9184 LOGW("duration is Non-Initialized !!!");
9185 player->duration = 0;
9188 /* update streaming service type */
9189 player->streaming_type = _mmplayer_get_stream_service_type(player);
9191 /* check duration is OK */
9192 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9193 /* FIXIT : find another way to get duration here. */
9194 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9200 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9202 /* update audio params
9203 NOTE : We need original audio params and it can be only obtained from src pad of audio
9204 decoder. Below code only valid when we are not using 'resampler' just before
9205 'audioconverter'. */
9206 GstCaps *caps_a = NULL;
9208 gint samplerate = 0, channels = 0;
9209 GstStructure *p = NULL;
9210 GstElement *aconv = NULL;
9212 LOGD("try to update audio attrs");
9214 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9216 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9217 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9218 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9219 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9221 LOGE("there is no audio converter");
9225 pad = gst_element_get_static_pad(aconv, "sink");
9228 LOGW("failed to get pad from audio converter");
9232 caps_a = gst_pad_get_current_caps(pad);
9234 LOGW("not ready to get audio caps");
9235 gst_object_unref(pad);
9239 p = gst_caps_get_structure(caps_a, 0);
9241 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9243 gst_structure_get_int(p, "rate", &samplerate);
9244 gst_structure_get_int(p, "channels", &channels);
9246 mm_player_set_attribute((MMHandleType)player, NULL,
9247 "content_audio_samplerate", samplerate,
9248 "content_audio_channels", channels, NULL);
9250 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9252 gst_caps_unref(caps_a);
9253 gst_object_unref(pad);
9259 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9261 LOGD("try to update video attrs");
9263 GstCaps *caps_v = NULL;
9267 GstStructure *p = NULL;
9269 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9270 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9272 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9274 LOGD("no videosink sink pad");
9278 caps_v = gst_pad_get_current_caps(pad);
9279 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9280 if (!caps_v && player->v_stream_caps) {
9281 caps_v = player->v_stream_caps;
9282 gst_caps_ref(caps_v);
9286 LOGD("no negitiated caps from videosink");
9287 gst_object_unref(pad);
9291 p = gst_caps_get_structure(caps_v, 0);
9292 gst_structure_get_int(p, "width", &width);
9293 gst_structure_get_int(p, "height", &height);
9295 mm_player_set_attribute((MMHandleType)player, NULL,
9296 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9298 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9300 SECURE_LOGD("width : %d height : %d", width, height);
9302 gst_caps_unref(caps_v);
9303 gst_object_unref(pad);
9306 mm_player_set_attribute((MMHandleType)player, NULL,
9307 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9308 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9315 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9317 gboolean ret = FALSE;
9318 guint64 data_size = 0;
9322 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9323 if (!player->duration)
9326 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9327 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9328 if (stat(path, &sb) == 0)
9329 data_size = (guint64)sb.st_size;
9331 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9332 data_size = player->http_content_size;
9335 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9338 guint64 bitrate = 0;
9339 guint64 msec_dur = 0;
9341 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9343 bitrate = data_size * 8 * 1000 / msec_dur;
9344 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9345 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9346 mm_player_set_attribute((MMHandleType)player, NULL,
9347 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9350 LOGD("player duration is less than 0");
9354 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9355 if (player->total_bitrate) {
9356 mm_player_set_attribute((MMHandleType)player, NULL,
9357 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9366 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9368 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9369 data->uri_type = uri_type;
9373 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9375 int ret = MM_ERROR_PLAYER_INVALID_URI;
9377 char *buffer = NULL;
9378 char *seperator = strchr(path, ',');
9379 char ext[100] = {0,}, size[100] = {0,};
9382 if ((buffer = strstr(path, "ext="))) {
9383 buffer += strlen("ext=");
9385 if (strlen(buffer)) {
9386 strncpy(ext, buffer, 99);
9388 if ((seperator = strchr(ext, ','))
9389 || (seperator = strchr(ext, ' '))
9390 || (seperator = strchr(ext, '\0'))) {
9391 seperator[0] = '\0';
9396 if ((buffer = strstr(path, "size="))) {
9397 buffer += strlen("size=");
9399 if (strlen(buffer) > 0) {
9400 strncpy(size, buffer, 99);
9402 if ((seperator = strchr(size, ','))
9403 || (seperator = strchr(size, ' '))
9404 || (seperator = strchr(size, '\0'))) {
9405 seperator[0] = '\0';
9408 mem_size = atoi(size);
9413 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9415 if (mem_size && param) {
9416 if (data->input_mem.buf)
9417 free(data->input_mem.buf);
9418 data->input_mem.buf = malloc(mem_size);
9420 if (data->input_mem.buf) {
9421 memcpy(data->input_mem.buf, param, mem_size);
9422 data->input_mem.len = mem_size;
9423 ret = MM_ERROR_NONE;
9425 LOGE("failed to alloc mem %d", mem_size);
9426 ret = MM_ERROR_PLAYER_INTERNAL;
9429 data->input_mem.offset = 0;
9430 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9437 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9439 gchar *location = NULL;
9442 int ret = MM_ERROR_NONE;
9444 if ((path = strstr(uri, "file://"))) {
9445 location = g_filename_from_uri(uri, NULL, &err);
9446 if (!location || (err != NULL)) {
9447 LOGE("Invalid URI '%s' for filesrc: %s", path,
9448 (err != NULL) ? err->message : "unknown error");
9452 MMPLAYER_FREEIF(location);
9454 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9455 return MM_ERROR_PLAYER_INVALID_URI;
9457 LOGD("path from uri: %s", location);
9460 path = (location != NULL) ? (location) : ((char *)uri);
9463 ret = _mmplayer_exist_file_path(path);
9465 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9466 if (ret == MM_ERROR_NONE) {
9467 if (_mmplayer_is_sdp_file(path)) {
9468 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9469 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9470 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9472 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9473 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9475 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9476 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9478 LOGE("invalid uri, could not play..");
9479 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9482 MMPLAYER_FREEIF(location);
9487 static mmplayer_video_decoded_data_info_t *
9488 __mmplayer_create_stream_from_pad(GstPad *pad)
9490 GstCaps *caps = NULL;
9491 GstStructure *structure = NULL;
9492 unsigned int fourcc = 0;
9493 const gchar *string_format = NULL;
9494 mmplayer_video_decoded_data_info_t *stream = NULL;
9496 MMPixelFormatType format;
9499 caps = gst_pad_get_current_caps(pad);
9501 LOGE("Caps is NULL.");
9506 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9508 structure = gst_caps_get_structure(caps, 0);
9509 gst_structure_get_int(structure, "width", &width);
9510 gst_structure_get_int(structure, "height", &height);
9511 string_format = gst_structure_get_string(structure, "format");
9514 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9515 format = _mmplayer_get_pixtype(fourcc);
9516 gst_video_info_from_caps(&info, caps);
9517 gst_caps_unref(caps);
9520 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9521 LOGE("Wrong condition!!");
9525 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9527 LOGE("failed to alloc mem for video data");
9531 stream->width = width;
9532 stream->height = height;
9533 stream->format = format;
9534 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9540 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9542 unsigned int pitch = 0;
9543 unsigned int size = 0;
9545 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9548 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9549 bo = gst_tizen_memory_get_bos(mem, index);
9551 stream->bo[index] = tbm_bo_ref(bo);
9553 LOGE("failed to get bo for index %d", index);
9556 for (index = 0; index < stream->plane_num; index++) {
9557 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9558 stream->stride[index] = pitch;
9560 stream->elevation[index] = size / pitch;
9562 stream->elevation[index] = stream->height;
9567 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9569 if (stream->format == MM_PIXEL_FORMAT_I420) {
9570 int ret = TBM_SURFACE_ERROR_NONE;
9571 tbm_surface_h surface;
9572 tbm_surface_info_s info;
9574 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9576 ret = tbm_surface_get_info(surface, &info);
9577 if (ret != TBM_SURFACE_ERROR_NONE) {
9578 tbm_surface_destroy(surface);
9582 tbm_surface_destroy(surface);
9583 stream->stride[0] = info.planes[0].stride;
9584 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9585 stream->stride[1] = info.planes[1].stride;
9586 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9587 stream->stride[2] = info.planes[2].stride;
9588 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9589 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9590 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9591 stream->stride[0] = stream->width * 4;
9592 stream->elevation[0] = stream->height;
9593 stream->bo_size = stream->stride[0] * stream->height;
9595 LOGE("Not support format %d", stream->format);
9603 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9605 tbm_bo_handle thandle;
9607 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9608 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9609 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9613 unsigned char *src = NULL;
9614 unsigned char *dest = NULL;
9615 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9617 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9619 LOGE("fail to gst_memory_map");
9623 if (!mapinfo.data) {
9624 LOGE("data pointer is wrong");
9628 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9629 if (!stream->bo[0]) {
9630 LOGE("Fail to tbm_bo_alloc!!");
9634 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9636 LOGE("thandle pointer is wrong");
9640 if (stream->format == MM_PIXEL_FORMAT_I420) {
9641 src_stride[0] = GST_ROUND_UP_4(stream->width);
9642 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9643 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9644 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9647 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9648 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9650 for (i = 0; i < 3; i++) {
9651 src = mapinfo.data + src_offset[i];
9652 dest = thandle.ptr + dest_offset[i];
9657 for (j = 0; j < stream->height >> k; j++) {
9658 memcpy(dest, src, stream->width>>k);
9659 src += src_stride[i];
9660 dest += stream->stride[i];
9663 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9664 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9666 LOGE("Not support format %d", stream->format);
9670 tbm_bo_unmap(stream->bo[0]);
9671 gst_memory_unmap(mem, &mapinfo);
9677 tbm_bo_unmap(stream->bo[0]);
9680 gst_memory_unmap(mem, &mapinfo);
9686 __mmplayer_set_pause_state(mmplayer_t *player)
9688 if (player->sent_bos)
9691 /* rtsp case, get content attrs by GstMessage */
9692 if (MMPLAYER_IS_RTSP_STREAMING(player))
9695 /* it's first time to update all content attrs. */
9696 _mmplayer_update_content_attrs(player, ATTR_ALL);
9700 __mmplayer_set_playing_state(mmplayer_t *player)
9702 gchar *audio_codec = NULL;
9704 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9705 /* initialize because auto resume is done well. */
9706 player->resumed_by_rewind = FALSE;
9707 player->playback_rate = 1.0;
9710 if (player->sent_bos)
9713 /* try to get content metadata */
9715 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9716 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9717 * legacy mmfw-player api
9719 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9721 if ((player->cmd == MMPLAYER_COMMAND_START)
9722 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9723 __mmplayer_handle_missed_plugin(player);
9726 /* check audio codec field is set or not
9727 * we can get it from typefinder or codec's caps.
9729 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9731 /* The codec format can't be sent for audio only case like amr, mid etc.
9732 * Because, parser don't make related TAG.
9733 * So, if it's not set yet, fill it with found data.
9736 if (g_strrstr(player->type, "audio/midi"))
9737 audio_codec = "MIDI";
9738 else if (g_strrstr(player->type, "audio/x-amr"))
9739 audio_codec = "AMR";
9740 else if (g_strrstr(player->type, "audio/mpeg")
9741 && !g_strrstr(player->type, "mpegversion=(int)1"))
9742 audio_codec = "AAC";
9744 audio_codec = "unknown";
9746 if (mm_player_set_attribute((MMHandleType)player, NULL,
9747 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9748 LOGE("failed to set attribute");
9750 LOGD("set audio codec type with caps");