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);
144 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
145 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
146 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
147 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
149 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
150 static void __mmplayer_release_misc(mmplayer_t *player);
151 static void __mmplayer_release_misc_post(mmplayer_t *player);
152 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
153 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
154 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
155 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
156 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
158 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
159 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
160 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
161 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
162 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
163 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
164 static gpointer __mmplayer_gapless_play_thread(gpointer data);
165 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
166 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
167 static void __mmplayer_release_dump_list(GList *dump_list);
168 static int __mmplayer_gst_realize(mmplayer_t *player);
169 static int __mmplayer_gst_unrealize(mmplayer_t *player);
170 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
171 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
174 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
175 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player);
176 static gboolean __mmplayer_deactivate_selector(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 static 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 GList *a_dec = player->audio_decoders;
674 for (; a_dec; a_dec = g_list_next(a_dec)) {
675 gchar *name = a_dec->data;
676 MMPLAYER_FREEIF(name);
678 g_list_free(player->audio_decoders);
679 player->audio_decoders = NULL;
682 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
687 void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state)
689 LOGI("set pipeline reconfigure state %d", state);
690 MMPLAYER_RECONFIGURE_LOCK(player);
691 player->gapless.reconfigure = state;
692 if (!state) /* wake up the waiting job */
693 MMPLAYER_RECONFIGURE_SIGNAL(player);
694 MMPLAYER_RECONFIGURE_UNLOCK(player);
698 __mmplayer_gapless_play_thread(gpointer data)
700 mmplayer_t *player = (mmplayer_t *)data;
701 mmplayer_gst_element_t *mainbin = NULL;
703 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
705 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
706 while (!player->gapless_play_thread_exit) {
707 LOGD("gapless play thread started. waiting for signal.");
708 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
710 LOGD("reconfigure pipeline for gapless play.");
712 if (player->gapless_play_thread_exit) {
713 _mmplayer_set_reconfigure_state(player, FALSE);
714 LOGD("exiting gapless play thread");
718 mainbin = player->pipeline->mainbin;
720 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
721 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
722 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
723 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
724 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
726 /* Initialize Player values */
727 __mmplayer_initialize_gapless_play(player);
729 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
731 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
737 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
739 GSource *source = NULL;
743 source = g_main_context_find_source_by_id(context, source_id);
744 if (source != NULL) {
745 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
746 g_source_destroy(source);
753 _mmplayer_watcher_removed_notify(gpointer data)
755 mmplayer_t *player = (mmplayer_t *)data;
756 MMPLAYER_RETURN_IF_FAIL(player);
758 MMPLAYER_BUS_WATCHER_LOCK(player);
759 player->bus_watcher = 0;
760 MMPLAYER_BUS_WATCHER_SIGNAL(player);
761 MMPLAYER_BUS_WATCHER_UNLOCK(player);
765 _mmplayer_bus_watcher_remove(MMHandleType hplayer)
767 mmplayer_t *player = (mmplayer_t *)hplayer;
770 MMPLAYER_RETURN_IF_FAIL(player);
772 /* disconnecting bus watch */
773 if (player->bus_watcher > 0) {
774 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
775 MMPLAYER_BUS_WATCHER_LOCK(player);
776 end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND;
777 while (player->bus_watcher > 0)
778 MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time);
779 MMPLAYER_BUS_WATCHER_UNLOCK(player);
781 g_mutex_clear(&player->bus_watcher_mutex);
782 g_cond_clear(&player->bus_watcher_cond);
789 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
791 mmplayer_t *player = (mmplayer_t *)hplayer;
792 GstMessage *msg = NULL;
793 GQueue *queue = NULL;
796 MMPLAYER_RETURN_IF_FAIL(player);
798 /* destroy the gst bus msg thread */
799 if (player->bus_msg_thread) {
800 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
801 player->bus_msg_thread_exit = TRUE;
802 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
803 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
805 LOGD("gst bus msg thread exit.");
806 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
807 player->bus_msg_thread = NULL;
809 g_mutex_clear(&player->bus_msg_thread_mutex);
810 g_cond_clear(&player->bus_msg_thread_cond);
813 g_mutex_lock(&player->bus_msg_q_lock);
814 queue = player->bus_msg_q;
815 while (!g_queue_is_empty(queue)) {
816 msg = (GstMessage *)g_queue_pop_head(queue);
821 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
822 gst_message_unref(msg);
824 g_mutex_unlock(&player->bus_msg_q_lock);
830 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
832 GstElement *parent = NULL;
834 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
835 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
838 MMPLAYER_FSINK_LOCK(player);
840 /* get parent of fakesink */
841 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
843 LOGD("fakesink already removed");
847 gst_element_set_locked_state(fakesink->gst, TRUE);
849 /* setting the state to NULL never returns async
850 * so no need to wait for completion of state transiton
852 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
853 LOGE("fakesink state change failure!");
854 /* FIXIT : should I return here? or try to proceed to next? */
857 /* remove fakesink from it's parent */
858 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
859 LOGE("failed to remove fakesink");
861 gst_object_unref(parent);
866 gst_object_unref(parent);
868 LOGD("state-holder removed");
870 gst_element_set_locked_state(fakesink->gst, FALSE);
872 MMPLAYER_FSINK_UNLOCK(player);
877 gst_element_set_locked_state(fakesink->gst, FALSE);
879 MMPLAYER_FSINK_UNLOCK(player);
883 static GstPadProbeReturn
884 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
886 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
887 return GST_PAD_PROBE_OK;
891 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
893 gint64 stop_running_time = 0;
894 gint64 position_running_time = 0;
898 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
899 if ((player->gapless.update_segment[idx] == TRUE) ||
900 !(player->track[idx].event_probe_id)) {
902 LOGW("[%d] skip", idx);
907 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
909 gst_segment_to_running_time(&player->gapless.segment[idx],
910 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
911 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
913 gst_segment_to_running_time(&player->gapless.segment[idx],
914 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
916 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
918 gst_segment_to_running_time(&player->gapless.segment[idx],
919 GST_FORMAT_TIME, player->duration);
922 position_running_time =
923 gst_segment_to_running_time(&player->gapless.segment[idx],
924 GST_FORMAT_TIME, player->gapless.segment[idx].position);
926 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
927 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
929 GST_TIME_ARGS(stop_running_time),
930 GST_TIME_ARGS(position_running_time),
931 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
932 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
934 position_running_time = MAX(position_running_time, stop_running_time);
935 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
936 GST_FORMAT_TIME, player->gapless.segment[idx].start);
937 position_running_time = MAX(0, position_running_time);
938 position = MAX(position, position_running_time);
942 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
943 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
944 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
946 player->gapless.start_time[stream_type] += position;
952 static GstPadProbeReturn
953 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
955 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
956 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
957 mmplayer_t *player = (mmplayer_t *)data;
958 GstCaps *caps = NULL;
959 GstStructure *str = NULL;
960 const gchar *name = NULL;
961 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
962 gboolean caps_ret = TRUE;
964 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
965 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
966 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
967 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
968 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
971 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
975 if (strstr(name, "audio")) {
976 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
977 } else if (strstr(name, "video")) {
978 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
980 /* text track is not supportable */
981 LOGE("invalid name %s", name);
985 switch (GST_EVENT_TYPE(event)) {
988 /* in case of gapless, drop eos event not to send it to sink */
989 if (player->gapless.reconfigure && !player->msg_posted) {
990 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
991 ret = GST_PAD_PROBE_DROP;
995 case GST_EVENT_STREAM_START:
997 __mmplayer_gst_selector_update_start_time(player, stream_type);
1000 case GST_EVENT_FLUSH_STOP:
1002 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1003 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1004 player->gapless.start_time[stream_type] = 0;
1007 case GST_EVENT_SEGMENT:
1012 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1013 gst_event_copy_segment(event, &segment);
1015 if (segment.format != GST_FORMAT_TIME)
1018 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1019 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1020 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1021 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1022 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1023 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1025 /* keep the all the segment ev to cover the seeking */
1026 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1027 player->gapless.update_segment[stream_type] = TRUE;
1029 if (!player->gapless.running)
1032 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1034 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1036 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1037 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1038 gst_event_unref(event);
1039 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1045 gdouble proportion = 0.0;
1046 GstClockTimeDiff diff = 0;
1047 GstClockTime timestamp = 0;
1048 gint64 running_time_diff = -1;
1049 GstQOSType type = 0;
1050 GstEvent *tmpev = NULL;
1052 running_time_diff = player->gapless.segment[stream_type].base;
1054 if (running_time_diff <= 0) /* don't need to adjust */
1057 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1058 gst_event_unref(event);
1060 if (timestamp < running_time_diff) {
1061 LOGW("QOS event from previous group");
1062 ret = GST_PAD_PROBE_DROP;
1067 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1068 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1069 stream_type, GST_TIME_ARGS(timestamp),
1070 GST_TIME_ARGS(running_time_diff),
1071 GST_TIME_ARGS(timestamp - running_time_diff));
1074 timestamp -= running_time_diff;
1076 /* That case is invalid for QoS events */
1077 if (diff < 0 && -diff > timestamp) {
1078 LOGW("QOS event from previous group");
1079 ret = GST_PAD_PROBE_DROP;
1083 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1084 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1094 gst_caps_unref(caps);
1098 /* create fakesink for audio or video path witout audiobin or videobin */
1100 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1102 GstElement *pipeline = NULL;
1103 GstElement *fakesink = NULL;
1104 GstPad *sinkpad = NULL;
1107 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1109 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1112 fakesink = gst_element_factory_make("fakesink", NULL);
1113 if (fakesink == NULL) {
1114 LOGE("failed to create fakesink");
1118 /* store it as it's sink element */
1119 __mmplayer_add_sink(player, fakesink);
1121 gst_bin_add(GST_BIN(pipeline), fakesink);
1124 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1126 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1128 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1129 LOGE("failed to link fakesink");
1130 gst_object_unref(GST_OBJECT(fakesink));
1134 if (strstr(name, "video")) {
1135 if (player->v_stream_caps) {
1136 gst_caps_unref(player->v_stream_caps);
1137 player->v_stream_caps = NULL;
1139 if (player->ini.set_dump_element_flag)
1140 __mmplayer_add_dump_buffer_probe(player, fakesink);
1143 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1144 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1148 gst_object_unref(GST_OBJECT(sinkpad));
1155 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1157 GstElement *pipeline = NULL;
1158 GstElement *selector = NULL;
1159 GstPad *srcpad = NULL;
1162 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1164 selector = gst_element_factory_make("input-selector", NULL);
1166 LOGE("failed to create input-selector");
1169 g_object_set(selector, "sync-streams", TRUE, NULL);
1171 player->pipeline->mainbin[elem_idx].id = elem_idx;
1172 player->pipeline->mainbin[elem_idx].gst = selector;
1174 /* player->track[stream_type].active_track_index = DEFAULT_TRACK; */
1176 srcpad = gst_element_get_static_pad(selector, "src");
1178 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1179 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1180 __mmplayer_gst_selector_blocked, NULL, NULL);
1181 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1182 __mmplayer_gst_selector_event_probe, player, NULL);
1184 gst_element_set_state(selector, GST_STATE_PAUSED);
1186 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1187 gst_bin_add(GST_BIN(pipeline), selector);
1189 gst_object_unref(GST_OBJECT(srcpad));
1196 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1198 mmplayer_t *player = (mmplayer_t *)data;
1199 GstElement *selector = NULL;
1200 GstCaps *caps = NULL;
1201 GstStructure *str = NULL;
1202 const gchar *name = NULL;
1203 GstPad *sinkpad = NULL;
1204 gboolean first_track = FALSE;
1205 gboolean caps_ret = TRUE;
1207 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1208 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1211 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1212 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1214 LOGD("pad-added signal handling");
1216 /* get mimetype from caps */
1217 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1221 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1223 LOGD("detected mimetype : %s", name);
1226 if (strstr(name, "video")) {
1228 gchar *caps_str = NULL;
1230 caps_str = gst_caps_to_string(caps);
1231 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1232 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1233 player->set_mode.video_zc = true;
1235 MMPLAYER_FREEIF(caps_str);
1237 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1238 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1240 LOGD("surface type : %d", stype);
1242 if (MMPLAYER_IS_MS_BUFF_SRC(player) || MMPLAYER_USE_URIDECODEBIN3(player)) {
1243 __mmplayer_gst_create_sinkbin(elem, pad, player);
1247 /* in case of exporting video frame, it requires the 360 video filter.
1248 * it will be handled in _no_more_pads(). */
1249 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1250 __mmplayer_gst_make_fakesink(player, pad, name);
1254 LOGD("video selector is required");
1255 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1256 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1257 } else if (strstr(name, "audio")) {
1258 gint samplerate = 0;
1261 if (MMPLAYER_IS_MS_BUFF_SRC(player) || MMPLAYER_USE_URIDECODEBIN3(player) || player->build_audio_offload) {
1262 if (player->build_audio_offload)
1263 player->no_more_pad = TRUE; /* remove state holder */
1264 __mmplayer_gst_create_sinkbin(elem, pad, player);
1268 gst_structure_get_int(str, "rate", &samplerate);
1269 gst_structure_get_int(str, "channels", &channels);
1271 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1272 __mmplayer_gst_make_fakesink(player, pad, name);
1276 LOGD("audio selector is required");
1277 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1278 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1280 } else if (strstr(name, "text")) {
1281 LOGD("text selector is required");
1282 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1283 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1285 LOGE("invalid caps info");
1289 /* check selector and create it */
1290 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1291 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1296 LOGD("input-selector is already created.");
1300 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1302 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1304 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1305 LOGE("failed to link selector");
1306 gst_object_unref(GST_OBJECT(selector));
1311 LOGD("this track will be activated");
1312 g_object_set(selector, "active-pad", sinkpad, NULL);
1315 if (!MMPLAYER_USE_URIDECODEBIN3(player))
1316 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1322 gst_caps_unref(caps);
1325 gst_object_unref(GST_OBJECT(sinkpad));
1333 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1335 GstPad *srcpad = NULL;
1338 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1340 LOGD("type %d", type);
1343 LOGD("there is no %d track", type);
1347 srcpad = gst_element_get_static_pad(selector, "src");
1349 LOGE("failed to get srcpad from selector");
1353 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1355 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1357 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1358 if (player->track[type].block_id) {
1359 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1360 player->track[type].block_id = 0;
1364 gst_object_unref(GST_OBJECT(srcpad));
1373 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1375 gint active_index = 0;
1378 MMPLAYER_RETURN_IF_FAIL(player);
1380 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1382 /* change track to active pad */
1383 active_index = player->track[type].active_track_index;
1384 if ((active_index != DEFAULT_TRACK) &&
1385 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1386 LOGW("failed to change %d type track to %d", type, active_index);
1387 player->track[type].active_track_index = DEFAULT_TRACK;
1391 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1392 mm_player_set_attribute((MMHandleType)player, NULL,
1393 "content_text_track_num", player->track[type].total_track_num,
1394 "current_text_track_index", player->track[type].active_track_index, NULL);
1401 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1404 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1406 if (!audio_selector) {
1407 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1409 /* in case the source is changed, output can be changed. */
1410 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1411 LOGD("remove previous audiobin if it exist");
1413 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1414 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1416 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1417 MMPLAYER_FREEIF(player->pipeline->audiobin);
1420 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1421 _mmplayer_pipeline_complete(NULL, player);
1426 /* apply the audio track information */
1427 if (!MMPLAYER_USE_URIDECODEBIN3(player))
1428 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1430 /* create audio sink path */
1431 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1432 LOGE("failed to create audio sink path");
1441 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1444 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1446 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1447 LOGD("text path is not supproted");
1451 /* apply the text track information */
1452 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1454 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1455 player->has_closed_caption = TRUE;
1457 /* create text decode path */
1458 player->no_more_pad = TRUE;
1460 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1461 LOGE("failed to create text sink path");
1470 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1472 gint64 dur_bytes = 0L;
1475 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1476 player->pipeline->mainbin && player->streamer, FALSE);
1478 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1479 LOGE("fail to get duration.");
1481 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1482 * use file information was already set on Q2 when it was created. */
1483 _mm_player_streaming_set_queue2(player->streamer,
1484 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1485 TRUE, /* use_buffering */
1486 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1487 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1494 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1496 mmplayer_t *player = NULL;
1497 GstElement *video_selector = NULL;
1498 GstElement *audio_selector = NULL;
1499 GstElement *text_selector = NULL;
1502 player = (mmplayer_t *)data;
1504 LOGD("no-more-pad signal handling");
1506 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1507 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1508 LOGW("player is shutting down");
1512 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1513 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1514 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1515 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1516 LOGE("failed to set queue2 buffering");
1521 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1522 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1523 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1525 if (!video_selector && !audio_selector && !text_selector) {
1526 LOGW("there is no selector");
1527 player->no_more_pad = TRUE;
1531 /* create video path followed by video-select */
1532 if (video_selector && !audio_selector && !text_selector)
1533 player->no_more_pad = TRUE;
1535 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1538 /* create audio path followed by audio-select */
1539 if (audio_selector && !text_selector)
1540 player->no_more_pad = TRUE;
1542 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1545 /* create text path followed by text-select */
1546 __mmplayer_create_text_sink_path(player, text_selector);
1549 _mmplayer_set_reconfigure_state(player, FALSE);
1554 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1556 gboolean ret = FALSE;
1557 GstElement *pipeline = NULL;
1558 GstPad *sinkpad = NULL;
1561 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1562 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1564 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1566 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1568 LOGE("failed to get pad from sinkbin");
1574 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1575 LOGE("failed to link sinkbin for reusing");
1576 goto EXIT; /* exit either pass or fail */
1580 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1581 LOGE("failed to set state(READY) to sinkbin");
1586 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1587 LOGE("failed to add sinkbin to pipeline");
1592 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1593 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1598 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1599 LOGE("failed to set state(PAUSED) to sinkbin");
1608 gst_object_unref(GST_OBJECT(sinkpad));
1616 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1618 mmplayer_t *player = NULL;
1619 GstCaps *caps = NULL;
1620 gchar *caps_str = NULL;
1621 GstStructure *str = NULL;
1622 const gchar *name = NULL;
1623 GstElement *sinkbin = NULL;
1624 gboolean reusing = FALSE;
1625 gboolean caps_ret = TRUE;
1626 gchar *sink_pad_name = "sink";
1629 player = (mmplayer_t *)data;
1632 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1633 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1635 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1639 caps_str = gst_caps_to_string(caps);
1641 LOGD("detected mimetype : %s", name);
1643 if (strstr(name, "audio")) {
1644 if (player->pipeline->audiobin == NULL) {
1645 const gchar *audio_format = gst_structure_get_string(str, "format");
1647 LOGD("original audio format %s", audio_format);
1648 mm_player_set_attribute((MMHandleType)player, NULL,
1649 "content_audio_format", audio_format, strlen(audio_format), NULL);
1652 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1653 LOGE("failed to create audiobin. continuing without audio");
1657 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1658 LOGD("creating audiobin success");
1661 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1662 LOGD("reusing audiobin");
1663 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1665 } else if (strstr(name, "video")) {
1666 /* 1. zero copy is updated at _decode_pad_added()
1667 * 2. NULL surface type is handled in _decode_pad_added() */
1668 LOGD("zero copy %d", player->set_mode.video_zc);
1669 if (player->pipeline->videobin == NULL) {
1670 int surface_type = 0;
1671 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1672 LOGD("display_surface_type (%d)", surface_type);
1674 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1675 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1676 LOGE("failed to acquire video overlay resource");
1680 player->interrupted_by_resource = FALSE;
1682 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1683 LOGE("failed to create videobin. continuing without video");
1687 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1688 LOGD("creating videosink bin success");
1691 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1692 LOGD("re-using videobin");
1693 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1695 } else if (strstr(name, "text")) {
1696 if (player->pipeline->textbin == NULL) {
1697 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1698 LOGE("failed to create text sink bin. continuing without text");
1702 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1703 player->textsink_linked = 1;
1704 LOGD("creating textsink bin success");
1706 if (!player->textsink_linked) {
1707 LOGD("re-using textbin");
1709 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1710 player->textsink_linked = 1;
1712 /* linked textbin exist which means that the external subtitle path exist already */
1713 LOGW("ignoring internal subtutle since external subtitle is available");
1716 sink_pad_name = "text_sink";
1718 LOGW("unknown mime type %s, ignoring it", name);
1722 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1725 LOGD("[handle: %p] success to create and link sink bin", player);
1727 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1728 * streaming task. if the task blocked, then buffer will not flow to the next element
1729 *(autoplugging element). so this is special hack for streaming. please try to remove it
1731 /* dec stream count. we can remove fakesink if it's zero */
1732 if (player->num_dynamic_pad)
1733 player->num_dynamic_pad--;
1735 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1737 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1738 _mmplayer_pipeline_complete(NULL, player);
1742 MMPLAYER_FREEIF(caps_str);
1745 gst_caps_unref(caps);
1751 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1753 int required_angle = 0; /* Angle required for straight view */
1754 int rotation_angle = 0;
1756 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1757 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1759 /* Counter clockwise */
1760 switch (orientation) {
1765 required_angle = 270;
1768 required_angle = 180;
1771 required_angle = 90;
1775 rotation_angle = display_angle + required_angle;
1776 if (rotation_angle >= 360)
1777 rotation_angle -= 360;
1779 /* chech if supported or not */
1780 if (rotation_angle % 90) {
1781 LOGD("not supported rotation angle = %d", rotation_angle);
1785 switch (rotation_angle) {
1787 *value = MM_DISPLAY_ROTATION_NONE;
1790 *value = MM_DISPLAY_ROTATION_90;
1793 *value = MM_DISPLAY_ROTATION_180;
1796 *value = MM_DISPLAY_ROTATION_270;
1800 LOGD("setting rotation property value : %d", *value);
1806 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1808 int display_rotation = 0;
1809 gchar *org_orient = NULL;
1810 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1813 LOGE("cannot get content attribute");
1814 return MM_ERROR_PLAYER_INTERNAL;
1817 if (display_angle) {
1818 /* update user roation */
1819 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1821 /* Counter clockwise */
1822 switch (display_rotation) {
1823 case MM_DISPLAY_ROTATION_NONE:
1826 case MM_DISPLAY_ROTATION_90:
1827 *display_angle = 90;
1829 case MM_DISPLAY_ROTATION_180:
1830 *display_angle = 180;
1832 case MM_DISPLAY_ROTATION_270:
1833 *display_angle = 270;
1836 LOGW("wrong angle type : %d", display_rotation);
1839 LOGD("check user angle: %d", *display_angle);
1843 /* Counter clockwise */
1844 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1847 if (!strcmp(org_orient, "rotate-90"))
1849 else if (!strcmp(org_orient, "rotate-180"))
1851 else if (!strcmp(org_orient, "rotate-270"))
1854 LOGD("original rotation is %s", org_orient);
1856 LOGD("content_video_orientation get fail");
1859 LOGD("check orientation: %d", *orientation);
1862 return MM_ERROR_NONE;
1865 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1867 int rotation_value = 0;
1868 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1869 int display_angle = 0;
1872 /* check video sinkbin is created */
1873 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1876 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1878 /* get rotation value to set */
1879 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1880 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1881 LOGD("set video param : rotate %d", rotation_value);
1884 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1886 MMHandleType attrs = 0;
1890 /* check video sinkbin is created */
1891 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1894 attrs = MMPLAYER_GET_ATTRS(player);
1895 MMPLAYER_RETURN_IF_FAIL(attrs);
1897 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1898 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1899 LOGD("set video param : visible %d", visible);
1902 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1904 MMHandleType attrs = 0;
1905 int display_method = 0;
1908 /* check video sinkbin is created */
1909 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1912 attrs = MMPLAYER_GET_ATTRS(player);
1913 MMPLAYER_RETURN_IF_FAIL(attrs);
1915 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1916 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1917 LOGD("set video param : method %d", display_method);
1920 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1922 MMHandleType attrs = 0;
1926 /* check video sinkbin is created */
1927 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1930 attrs = MMPLAYER_GET_ATTRS(player);
1931 MMPLAYER_RETURN_IF_FAIL(attrs);
1933 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1934 MMPLAYER_RETURN_IF_FAIL(handle);
1936 gst_video_overlay_set_video_roi_area(
1937 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1938 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1939 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1940 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1943 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1945 MMHandleType attrs = 0;
1950 int win_roi_width = 0;
1951 int win_roi_height = 0;
1954 /* check video sinkbin is created */
1955 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1958 attrs = MMPLAYER_GET_ATTRS(player);
1959 MMPLAYER_RETURN_IF_FAIL(attrs);
1961 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1962 MMPLAYER_RETURN_IF_FAIL(handle);
1964 /* It should be set after setting window */
1965 mm_attrs_multiple_get(attrs, NULL,
1966 "display_win_roi_x", &win_roi_x,
1967 "display_win_roi_y", &win_roi_y,
1968 "display_win_roi_width", &win_roi_width,
1969 "display_win_roi_height", &win_roi_height, NULL);
1971 /* After setting window handle, set display roi area */
1972 gst_video_overlay_set_display_roi_area(
1973 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1974 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1975 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1976 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1979 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1981 MMHandleType attrs = 0;
1984 /* check video sinkbin is created */
1985 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1988 attrs = MMPLAYER_GET_ATTRS(player);
1989 MMPLAYER_RETURN_IF_FAIL(attrs);
1991 /* common case if using overlay surface */
1992 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1993 MMPLAYER_RETURN_IF_FAIL(handle);
1995 /* default is using wl_surface_id */
1996 LOGD("set video param : wl_surface_id %d", handle);
1997 gst_video_overlay_set_wl_window_wl_surface_id(
1998 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2003 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2005 gboolean update_all_param = FALSE;
2009 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
2010 LOGW("videosink is not ready yet");
2011 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2014 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2015 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2016 return MM_ERROR_PLAYER_INTERNAL;
2019 LOGD("param_name : %s", param_name);
2020 if (!g_strcmp0(param_name, "update_all_param"))
2021 update_all_param = TRUE;
2023 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2024 __mmplayer_video_param_set_display_overlay(player);
2025 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2026 __mmplayer_video_param_set_display_method(player);
2027 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2028 __mmplayer_video_param_set_display_visible(player);
2029 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2030 __mmplayer_video_param_set_display_rotation(player);
2031 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2032 __mmplayer_video_param_set_roi_area(player);
2033 if (update_all_param)
2034 __mmplayer_video_param_set_video_roi_area(player);
2038 return MM_ERROR_NONE;
2042 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2044 gboolean disable_overlay = FALSE;
2045 mmplayer_t *player = (mmplayer_t *)hplayer;
2048 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2049 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2050 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2051 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2053 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2054 LOGW("Display control is not supported");
2055 return MM_ERROR_PLAYER_INTERNAL;
2058 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2060 if (audio_only == (bool)disable_overlay) {
2061 LOGE("It's the same with current setting: (%d)", audio_only);
2062 return MM_ERROR_NONE;
2066 LOGE("disable overlay");
2067 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2069 /* release overlay resource */
2070 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2071 LOGE("failed to release overlay resource");
2075 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2076 LOGE("failed to acquire video overlay resource");
2079 player->interrupted_by_resource = FALSE;
2081 LOGD("enable overlay");
2082 __mmplayer_video_param_set_display_overlay(player);
2083 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2088 return MM_ERROR_NONE;
2092 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2094 mmplayer_t *player = (mmplayer_t *)hplayer;
2095 gboolean disable_overlay = FALSE;
2099 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2100 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2101 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2102 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2103 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2105 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2106 LOGW("Display control is not supported");
2107 return MM_ERROR_PLAYER_INTERNAL;
2110 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2112 *paudio_only = (bool)disable_overlay;
2114 LOGD("audio_only : %d", *paudio_only);
2118 return MM_ERROR_NONE;
2122 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2124 GList *bucket = element_bucket;
2125 mmplayer_gst_element_t *element = NULL;
2126 mmplayer_gst_element_t *prv_element = NULL;
2127 GstElement *tee_element = NULL;
2128 gint successful_link_count = 0;
2132 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2134 prv_element = (mmplayer_gst_element_t *)bucket->data;
2135 bucket = bucket->next;
2137 for (; bucket; bucket = bucket->next) {
2138 element = (mmplayer_gst_element_t *)bucket->data;
2140 if (element && element->gst) {
2141 if (prv_element && prv_element->gst) {
2142 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2144 prv_element->gst = tee_element;
2146 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2147 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2148 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2152 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2153 LOGD("linking [%s] to [%s] success",
2154 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2155 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2156 successful_link_count++;
2157 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2158 LOGD("keep audio-tee element for next audio pipeline branch");
2159 tee_element = prv_element->gst;
2162 LOGD("linking [%s] to [%s] failed",
2163 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2164 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2170 prv_element = element;
2175 return successful_link_count;
2179 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2181 GList *bucket = element_bucket;
2182 mmplayer_gst_element_t *element = NULL;
2183 int successful_add_count = 0;
2187 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2188 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2190 for (; bucket; bucket = bucket->next) {
2191 element = (mmplayer_gst_element_t *)bucket->data;
2193 if (element && element->gst) {
2194 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2195 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2196 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2197 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2200 successful_add_count++;
2206 return successful_add_count;
2210 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2212 mmplayer_t *player = (mmplayer_t *)data;
2213 GstCaps *caps = NULL;
2214 GstStructure *str = NULL;
2216 gboolean caps_ret = TRUE;
2220 MMPLAYER_RETURN_IF_FAIL(pad);
2221 MMPLAYER_RETURN_IF_FAIL(unused);
2222 MMPLAYER_RETURN_IF_FAIL(data);
2224 caps = gst_pad_get_current_caps(pad);
2228 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2232 LOGD("name = %s", name);
2234 if (strstr(name, "audio")) {
2235 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2237 if (player->audio_stream_changed_cb) {
2238 LOGE("call the audio stream changed cb");
2239 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2241 } else if (strstr(name, "video")) {
2242 if ((name = gst_structure_get_string(str, "format")))
2243 player->set_mode.video_zc = name[0] == 'S';
2245 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2246 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2248 LOGW("invalid caps info");
2253 gst_caps_unref(caps);
2261 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2266 MMPLAYER_RETURN_IF_FAIL(player);
2268 if (player->audio_stream_buff_list) {
2269 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2270 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2273 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2274 __mmplayer_audio_stream_send_data(player, tmp);
2276 MMPLAYER_FREEIF(tmp->pcm_data);
2277 MMPLAYER_FREEIF(tmp);
2280 g_list_free(player->audio_stream_buff_list);
2281 player->audio_stream_buff_list = NULL;
2288 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2290 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2293 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2295 audio_stream.bitrate = a_buffer->bitrate;
2296 audio_stream.channel = a_buffer->channel;
2297 audio_stream.channel_mask = a_buffer->channel_mask;
2298 audio_stream.data_size = a_buffer->data_size;
2299 audio_stream.data = a_buffer->pcm_data;
2300 audio_stream.pcm_format = a_buffer->pcm_format;
2302 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2304 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2310 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2312 mmplayer_t *player = (mmplayer_t *)data;
2313 const gchar *pcm_format = NULL;
2316 guint64 channel_mask = 0;
2317 void *a_data = NULL;
2319 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2320 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2324 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2326 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2327 a_data = mapinfo.data;
2328 a_size = mapinfo.size;
2330 GstCaps *caps = gst_pad_get_current_caps(pad);
2331 GstStructure *structure = gst_caps_get_structure(caps, 0);
2333 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2335 pcm_format = gst_structure_get_string(structure, "format");
2336 gst_structure_get_int(structure, "rate", &rate);
2337 gst_structure_get_int(structure, "channels", &channel);
2338 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2339 gst_caps_unref(GST_CAPS(caps));
2341 /* In case of the sync is false, use buffer list. *
2342 * The num of buffer list depends on the num of audio channels */
2343 if (player->audio_stream_buff_list) {
2344 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2345 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2347 if (channel_mask == tmp->channel_mask) {
2349 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2351 if (tmp->data_size + a_size < tmp->buff_size) {
2352 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2353 tmp->data_size += a_size;
2355 /* send data to client */
2356 __mmplayer_audio_stream_send_data(player, tmp);
2358 if (a_size > tmp->buff_size) {
2359 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2360 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2361 if (tmp->pcm_data == NULL) {
2362 LOGE("failed to realloc data.");
2365 tmp->buff_size = a_size;
2367 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2368 memcpy(tmp->pcm_data, a_data, a_size);
2369 tmp->data_size = a_size;
2374 LOGE("data is empty in list.");
2380 /* create new audio stream data for newly found audio channel */
2381 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2382 if (a_buffer == NULL) {
2383 LOGE("failed to alloc data.");
2386 a_buffer->bitrate = rate;
2387 a_buffer->channel = channel;
2388 a_buffer->channel_mask = channel_mask;
2389 a_buffer->data_size = a_size;
2390 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2392 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2393 /* If sync is FALSE, use buffer list to reduce the IPC. */
2394 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2395 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2396 if (a_buffer->pcm_data == NULL) {
2397 LOGE("failed to alloc data.");
2398 MMPLAYER_FREEIF(a_buffer);
2401 memcpy(a_buffer->pcm_data, a_data, a_size);
2403 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2405 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2407 /* If sync is TRUE, send data directly. */
2408 a_buffer->pcm_data = a_data;
2409 __mmplayer_audio_stream_send_data(player, a_buffer);
2410 MMPLAYER_FREEIF(a_buffer);
2414 gst_buffer_unmap(buffer, &mapinfo);
2419 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2421 mmplayer_t *player = (mmplayer_t *)data;
2422 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2423 GstPad *sinkpad = NULL;
2424 GstElement *queue = NULL, *sink = NULL;
2427 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2429 queue = gst_element_factory_make("queue", NULL);
2430 if (queue == NULL) {
2431 LOGD("fail make queue");
2435 sink = gst_element_factory_make("fakesink", NULL);
2437 LOGD("fail make fakesink");
2441 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2443 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2444 LOGW("failed to link queue & sink");
2448 sinkpad = gst_element_get_static_pad(queue, "sink");
2450 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2451 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2455 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2457 gst_object_unref(sinkpad);
2458 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2459 g_object_set(sink, "sync", TRUE, NULL);
2460 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2462 /* keep the first sink reference only */
2463 if (!audiobin[MMPLAYER_A_SINK].gst) {
2464 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2465 audiobin[MMPLAYER_A_SINK].gst = sink;
2469 _mmplayer_add_signal_connection(player,
2471 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2473 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2476 __mmplayer_add_sink(player, sink);
2478 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2479 LOGE("failed to sync state");
2483 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2484 LOGE("failed to sync state");
2492 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2494 gst_object_unref(GST_OBJECT(queue));
2498 gst_object_unref(GST_OBJECT(sink));
2502 gst_object_unref(GST_OBJECT(sinkpad));
2510 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2512 mmplayer_t *player = (mmplayer_t *)data;
2515 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2517 player->no_more_pad = TRUE;
2518 _mmplayer_pipeline_complete(NULL, player);
2525 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2527 #define MAX_PROPS_LEN 128
2528 mmplayer_gst_element_t *audiobin = NULL;
2529 gint latency_mode = 0;
2530 gchar *stream_type = NULL;
2531 gchar *latency = NULL;
2533 gchar stream_props[MAX_PROPS_LEN] = {0,};
2534 GstStructure *props = NULL;
2537 * It should be set after player creation through attribute.
2538 * But, it can not be changed during playing.
2541 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2543 audiobin = player->pipeline->audiobin;
2545 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2546 if (player->sound.mute) {
2547 LOGD("mute enabled");
2548 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2551 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2552 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2555 snprintf(stream_props, sizeof(stream_props) - 1,
2556 "props,application.process.id.origin=%d", player->client_pid);
2558 snprintf(stream_props, sizeof(stream_props) - 1,
2559 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2560 stream_type, stream_id, player->client_pid);
2562 props = gst_structure_from_string(stream_props, NULL);
2563 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2564 LOGI("props result[%s].", stream_props);
2565 gst_structure_free(props);
2567 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2569 switch (latency_mode) {
2570 case AUDIO_LATENCY_MODE_LOW:
2571 latency = g_strdup("low");
2573 case AUDIO_LATENCY_MODE_MID:
2574 latency = g_strdup("mid");
2576 case AUDIO_LATENCY_MODE_HIGH:
2577 latency = g_strdup("high");
2580 latency = g_strdup("mid");
2584 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2586 LOGD("audiosink property - latency=%s", latency);
2588 MMPLAYER_FREEIF(latency);
2594 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2596 mmplayer_gst_element_t *audiobin = NULL;
2599 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2600 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2602 audiobin = player->pipeline->audiobin;
2604 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2605 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2606 LOGE("failed to create media stream info");
2607 return MM_ERROR_PLAYER_INTERNAL;
2610 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2612 if (player->video360_yaw_radians <= M_PI &&
2613 player->video360_yaw_radians >= -M_PI &&
2614 player->video360_pitch_radians <= M_PI_2 &&
2615 player->video360_pitch_radians >= -M_PI_2) {
2616 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2617 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2618 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2619 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2620 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2621 "source-orientation-y", player->video360_metadata.init_view_heading,
2622 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2626 return MM_ERROR_NONE;
2630 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2632 mmplayer_gst_element_t *audiobin = NULL;
2633 GstPad *sink_pad = NULL;
2634 GstCaps *acaps = NULL;
2636 int pitch_control = 0;
2637 double pitch_value = 1.0;
2640 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2641 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2643 audiobin = player->pipeline->audiobin;
2645 LOGD("make element for normal audio playback");
2647 /* audio bin structure for playback. {} means optional.
2648 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2650 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2651 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2654 /* for pitch control */
2655 mm_attrs_multiple_get(player->attrs, NULL,
2656 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2657 MM_PLAYER_PITCH_VALUE, &pitch_value,
2660 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2661 if (pitch_control && (player->videodec_linked == 0)) {
2662 GstElementFactory *factory;
2664 factory = gst_element_factory_find("pitch");
2666 gst_object_unref(factory);
2669 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2672 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2673 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2675 LOGW("there is no pitch element");
2680 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2682 /* replaygain volume */
2683 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2684 if (player->sound.rg_enable)
2685 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2687 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2690 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2692 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2693 /* currently, only openalsink uses volume element */
2694 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2695 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2697 if (player->sound.mute) {
2698 LOGD("mute enabled");
2699 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2703 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2705 /* audio effect element. if audio effect is enabled */
2706 if ((strcmp(player->ini.audioeffect_element, ""))
2708 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2709 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2711 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2713 if ((!player->bypass_audio_effect)
2714 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2715 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2716 if (!_mmplayer_audio_effect_custom_apply(player))
2717 LOGI("apply audio effect(custom) setting success");
2721 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2722 && (player->set_mode.rich_audio)) {
2723 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2727 /* create audio sink */
2728 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2729 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2730 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2732 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2733 if (player->is_360_feature_enabled &&
2734 player->is_content_spherical &&
2736 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2737 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2738 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2740 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2742 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2744 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2745 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2746 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2747 gst_caps_unref(acaps);
2749 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2751 player->is_openal_plugin_used = TRUE;
2753 if (player->is_360_feature_enabled && player->is_content_spherical)
2754 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2755 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2758 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2759 (player->videodec_linked && player->ini.use_system_clock)) {
2760 LOGD("system clock will be used.");
2761 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2764 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2765 __mmplayer_gst_set_pulsesink_property(player);
2766 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2767 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2772 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2773 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2775 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2776 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2777 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2778 gst_object_unref(GST_OBJECT(sink_pad));
2780 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2783 return MM_ERROR_NONE;
2785 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2787 return MM_ERROR_PLAYER_INTERNAL;
2791 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2793 mmplayer_gst_element_t *audiobin = NULL;
2794 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2796 gchar *dst_format = NULL;
2798 int dst_samplerate = 0;
2799 int dst_channels = 0;
2800 GstCaps *caps = NULL;
2801 char *caps_str = NULL;
2804 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2805 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2807 audiobin = player->pipeline->audiobin;
2809 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2811 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2813 [case 1] extract interleave audio pcm without playback
2814 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2815 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2817 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2819 [case 2] deinterleave for each channel without playback
2820 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2821 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2823 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2824 - fakesink (sync or not)
2827 [case 3] [case 1(sync only)] + playback
2828 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2830 * src - ... - tee - queue1 - playback path
2831 - queue2 - [case1 pipeline with sync]
2833 [case 4] [case 2(sync only)] + playback
2834 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2836 * src - ... - tee - queue1 - playback path
2837 - queue2 - [case2 pipeline with sync]
2841 /* 1. create tee and playback path
2842 'tee' should be added at first to copy the decoded stream
2844 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2845 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2846 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2848 /* tee - path 1 : for playback path */
2849 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2850 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2852 /* tee - path 2 : for extract path */
2853 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2854 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2857 /* if there is tee, 'tee - path 2' is linked here */
2859 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2862 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2864 /* 2. decide the extract pcm format */
2865 mm_attrs_multiple_get(player->attrs, NULL,
2866 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2867 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2868 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2871 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2872 dst_format, dst_len, dst_samplerate, dst_channels);
2874 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2875 mm_attrs_multiple_get(player->attrs, NULL,
2876 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2877 "content_audio_samplerate", &dst_samplerate,
2878 "content_audio_channels", &dst_channels,
2881 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2882 dst_format, dst_len, dst_samplerate, dst_channels);
2884 /* If there is no enough information, set it to platform default value. */
2885 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2886 LOGD("set platform default format");
2887 dst_format = DEFAULT_PCM_OUT_FORMAT;
2889 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2890 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2893 /* 3. create capsfilter */
2894 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2895 caps = gst_caps_new_simple("audio/x-raw",
2896 "format", G_TYPE_STRING, dst_format,
2897 "rate", G_TYPE_INT, dst_samplerate,
2898 "channels", G_TYPE_INT, dst_channels,
2901 caps_str = gst_caps_to_string(caps);
2902 LOGD("new caps : %s", caps_str);
2904 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2907 gst_caps_unref(caps);
2908 MMPLAYER_FREEIF(caps_str);
2910 /* 4-1. create deinterleave to extract pcm for each channel */
2911 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2912 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2913 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2915 /* audiosink will be added after getting signal for each channel */
2916 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2917 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2918 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2919 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2920 player->no_more_pad = FALSE;
2922 /* 4-2. create fakesink to extract interlevaed pcm */
2923 LOGD("add audio fakesink for interleaved audio");
2924 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2925 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2926 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2927 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2929 _mmplayer_add_signal_connection(player,
2930 G_OBJECT(audiobin[extract_sink_id].gst),
2931 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2933 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2936 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2940 return MM_ERROR_NONE;
2942 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2944 return MM_ERROR_PLAYER_INTERNAL;
2948 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2950 int ret = MM_ERROR_NONE;
2951 mmplayer_gst_element_t *audiobin = NULL;
2952 GList *element_bucket = NULL;
2955 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2956 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2958 audiobin = player->pipeline->audiobin;
2960 if (player->build_audio_offload) { /* skip all the audio filters */
2961 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2963 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2964 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2965 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2967 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2971 /* FIXME: need to mention the supportable condition at API reference */
2972 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2973 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2975 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2977 if (ret != MM_ERROR_NONE)
2980 LOGD("success to make audio bin element");
2981 *bucket = element_bucket;
2984 return MM_ERROR_NONE;
2987 LOGE("failed to make audio bin element");
2988 g_list_free(element_bucket);
2992 return MM_ERROR_PLAYER_INTERNAL;
2996 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2998 mmplayer_gst_element_t *first_element = NULL;
2999 mmplayer_gst_element_t *audiobin = NULL;
3001 GstPad *ghostpad = NULL;
3002 GList *element_bucket = NULL;
3006 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3009 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3011 LOGE("failed to allocate memory for audiobin");
3012 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3016 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3017 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3018 if (!audiobin[MMPLAYER_A_BIN].gst) {
3019 LOGE("failed to create audiobin");
3024 player->pipeline->audiobin = audiobin;
3026 /* create audio filters and audiosink */
3027 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3030 /* adding created elements to bin */
3031 LOGD("adding created elements to bin");
3032 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3035 /* linking elements in the bucket by added order. */
3036 LOGD("Linking elements in the bucket by added order.");
3037 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3040 /* get first element's sinkpad for creating ghostpad */
3041 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3042 if (!first_element) {
3043 LOGE("failed to get first elem");
3047 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3049 LOGE("failed to get pad from first element of audiobin");
3053 ghostpad = gst_ghost_pad_new("sink", pad);
3055 LOGE("failed to create ghostpad");
3059 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3060 LOGE("failed to add ghostpad to audiobin");
3064 gst_object_unref(pad);
3066 g_list_free(element_bucket);
3069 return MM_ERROR_NONE;
3072 LOGD("ERROR : releasing audiobin");
3075 gst_object_unref(GST_OBJECT(pad));
3078 gst_object_unref(GST_OBJECT(ghostpad));
3081 g_list_free(element_bucket);
3083 /* release element which are not added to bin */
3084 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3085 /* NOTE : skip bin */
3086 if (audiobin[i].gst) {
3087 GstObject *parent = NULL;
3088 parent = gst_element_get_parent(audiobin[i].gst);
3091 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3092 audiobin[i].gst = NULL;
3094 gst_object_unref(GST_OBJECT(parent));
3098 /* release audiobin with it's childs */
3099 if (audiobin[MMPLAYER_A_BIN].gst)
3100 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3102 MMPLAYER_FREEIF(audiobin);
3104 player->pipeline->audiobin = NULL;
3106 return MM_ERROR_PLAYER_INTERNAL;
3110 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3112 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3116 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3118 int ret = MM_ERROR_NONE;
3120 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3121 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3123 MMPLAYER_VIDEO_BO_LOCK(player);
3125 if (player->video_bo_list) {
3126 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3127 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3128 if (tmp && tmp->bo == bo) {
3130 LOGD("release bo %p", bo);
3131 tbm_bo_unref(tmp->bo);
3132 MMPLAYER_VIDEO_BO_UNLOCK(player);
3133 MMPLAYER_VIDEO_BO_SIGNAL(player);
3138 /* hw codec is running or the list was reset for DRC. */
3139 LOGW("there is no bo list.");
3141 MMPLAYER_VIDEO_BO_UNLOCK(player);
3143 LOGW("failed to find bo %p", bo);
3148 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3153 MMPLAYER_RETURN_IF_FAIL(player);
3155 MMPLAYER_VIDEO_BO_LOCK(player);
3156 if (player->video_bo_list) {
3157 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3158 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3159 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3162 tbm_bo_unref(tmp->bo);
3166 g_list_free(player->video_bo_list);
3167 player->video_bo_list = NULL;
3169 player->video_bo_size = 0;
3170 MMPLAYER_VIDEO_BO_UNLOCK(player);
3177 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3180 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3181 gboolean ret = TRUE;
3183 /* check DRC, if it is, destroy the prev bo list to create again */
3184 if (player->video_bo_size != size) {
3185 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3186 __mmplayer_video_stream_destroy_bo_list(player);
3187 player->video_bo_size = size;
3190 MMPLAYER_VIDEO_BO_LOCK(player);
3192 if ((!player->video_bo_list) ||
3193 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3195 /* create bo list */
3197 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3199 if (player->video_bo_list) {
3200 /* if bo list did not created all, try it again. */
3201 idx = g_list_length(player->video_bo_list);
3202 LOGD("bo list exist(len: %d)", idx);
3205 for (; idx < player->ini.num_of_video_bo; idx++) {
3206 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3208 LOGE("Fail to alloc bo_info.");
3211 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3213 LOGE("Fail to tbm_bo_alloc.");
3214 MMPLAYER_FREEIF(bo_info);
3217 bo_info->used = FALSE;
3218 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3221 /* update video num buffers */
3222 LOGD("video_num_buffers : %d", idx);
3223 mm_player_set_attribute((MMHandleType)player, NULL,
3224 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3225 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3229 MMPLAYER_VIDEO_BO_UNLOCK(player);
3235 /* get bo from list*/
3236 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3237 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3238 if (tmp && (tmp->used == FALSE)) {
3239 LOGD("found bo %p to use", tmp->bo);
3241 MMPLAYER_VIDEO_BO_UNLOCK(player);
3242 return tbm_bo_ref(tmp->bo);
3246 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3247 MMPLAYER_VIDEO_BO_UNLOCK(player);
3251 if (player->ini.video_bo_timeout <= 0) {
3252 MMPLAYER_VIDEO_BO_WAIT(player);
3254 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3255 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3262 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3264 mmplayer_t *player = (mmplayer_t *)data;
3266 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3268 /* send prerolled pkt */
3269 player->video_stream_prerolled = false;
3271 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3273 /* not to send prerolled pkt again */
3274 player->video_stream_prerolled = true;
3278 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3280 mmplayer_t *player = (mmplayer_t *)data;
3281 mmplayer_video_decoded_data_info_t *stream = NULL;
3282 GstMemory *mem = NULL;
3285 MMPLAYER_RETURN_IF_FAIL(player);
3286 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3288 if (player->video_stream_prerolled) {
3289 player->video_stream_prerolled = false;
3290 LOGD("skip the prerolled pkt not to send it again");
3294 /* clear stream data structure */
3295 stream = __mmplayer_create_stream_from_pad(pad);
3297 LOGE("failed to alloc stream");
3301 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3303 /* set size and timestamp */
3304 mem = gst_buffer_peek_memory(buffer, 0);
3305 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3306 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3308 /* check zero-copy */
3309 if (player->set_mode.video_zc &&
3310 player->set_mode.video_export &&
3311 gst_is_tizen_memory(mem)) {
3312 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3313 stream->internal_buffer = gst_buffer_ref(buffer);
3314 } else { /* sw codec */
3315 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3318 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3322 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3323 LOGE("failed to send video decoded data.");
3330 LOGE("release video stream resource.");
3331 if (gst_is_tizen_memory(mem)) {
3333 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3335 tbm_bo_unref(stream->bo[i]);
3338 /* unref gst buffer */
3339 if (stream->internal_buffer)
3340 gst_buffer_unref(stream->internal_buffer);
3343 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3345 MMPLAYER_FREEIF(stream);
3350 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3352 mmplayer_gst_element_t *videobin = NULL;
3355 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3357 videobin = player->pipeline->videobin;
3359 /* Set spatial media metadata and/or user settings to the element.
3361 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3362 "projection-type", player->video360_metadata.projection_type, NULL);
3364 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3365 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3367 if (player->video360_metadata.full_pano_width_pixels &&
3368 player->video360_metadata.full_pano_height_pixels &&
3369 player->video360_metadata.cropped_area_image_width &&
3370 player->video360_metadata.cropped_area_image_height) {
3371 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3372 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3373 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3374 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3375 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3376 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3377 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3381 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3382 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3383 "horizontal-fov", player->video360_horizontal_fov,
3384 "vertical-fov", player->video360_vertical_fov, NULL);
3387 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3388 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3389 "zoom", 1.0f / player->video360_zoom, NULL);
3392 if (player->video360_yaw_radians <= M_PI &&
3393 player->video360_yaw_radians >= -M_PI &&
3394 player->video360_pitch_radians <= M_PI_2 &&
3395 player->video360_pitch_radians >= -M_PI_2) {
3396 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3397 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3398 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3399 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3400 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3401 "pose-yaw", player->video360_metadata.init_view_heading,
3402 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3405 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3406 "passthrough", !player->is_video360_enabled, NULL);
3413 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3415 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3416 GList *element_bucket = NULL;
3419 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3421 /* create video360 filter */
3422 if (player->is_360_feature_enabled && player->is_content_spherical) {
3423 LOGD("create video360 element");
3424 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3425 __mmplayer_gst_set_video360_property(player);
3429 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3430 LOGD("skip creating the videoconv and rotator");
3431 return MM_ERROR_NONE;
3434 /* in case of sw codec & overlay surface type, except 360 playback.
3435 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3436 LOGD("create video converter: %s", video_csc);
3437 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3440 *bucket = element_bucket;
3442 return MM_ERROR_NONE;
3444 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3445 g_list_free(element_bucket);
3449 return MM_ERROR_PLAYER_INTERNAL;
3453 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3455 gchar *factory_name = NULL;
3457 switch (surface_type) {
3458 case MM_DISPLAY_SURFACE_OVERLAY:
3459 if (strlen(player->ini.videosink_element_overlay) > 0)
3460 factory_name = player->ini.videosink_element_overlay;
3462 case MM_DISPLAY_SURFACE_REMOTE:
3463 case MM_DISPLAY_SURFACE_NULL:
3464 if (strlen(player->ini.videosink_element_fake) > 0)
3465 factory_name = player->ini.videosink_element_fake;
3468 LOGE("unidentified surface type");
3472 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3473 return factory_name;
3477 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3479 gchar *factory_name = NULL;
3480 mmplayer_gst_element_t *videobin = NULL;
3485 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3487 videobin = player->pipeline->videobin;
3488 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3490 attrs = MMPLAYER_GET_ATTRS(player);
3492 LOGE("cannot get content attribute");
3493 return MM_ERROR_PLAYER_INTERNAL;
3496 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3497 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3498 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3499 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3500 "use-tbm", use_tbm, NULL);
3503 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3504 return MM_ERROR_PLAYER_INTERNAL;
3506 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3509 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3510 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3513 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3515 LOGD("disable last-sample");
3516 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3519 if (player->set_mode.video_export) {
3521 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3522 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3523 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3525 _mmplayer_add_signal_connection(player,
3526 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3527 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3529 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3532 _mmplayer_add_signal_connection(player,
3533 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3534 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3536 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3540 if (videobin[MMPLAYER_V_SINK].gst) {
3541 GstPad *sink_pad = NULL;
3542 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3544 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3545 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3546 gst_object_unref(GST_OBJECT(sink_pad));
3548 LOGE("failed to get sink pad from videosink");
3552 return MM_ERROR_NONE;
3557 * - video overlay surface(arm/x86) : tizenwlsink
3560 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3563 GList *element_bucket = NULL;
3564 mmplayer_gst_element_t *first_element = NULL;
3565 mmplayer_gst_element_t *videobin = NULL;
3566 gchar *videosink_factory_name = NULL;
3569 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3572 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3574 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3576 player->pipeline->videobin = videobin;
3579 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3580 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3581 if (!videobin[MMPLAYER_V_BIN].gst) {
3582 LOGE("failed to create videobin");
3586 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3589 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3590 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3592 /* additional setting for sink plug-in */
3593 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3594 LOGE("failed to set video property");
3598 /* store it as it's sink element */
3599 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3601 /* adding created elements to bin */
3602 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3603 LOGE("failed to add elements");
3607 /* Linking elements in the bucket by added order */
3608 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3609 LOGE("failed to link elements");
3613 /* get first element's sinkpad for creating ghostpad */
3614 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3615 if (!first_element) {
3616 LOGE("failed to get first element from bucket");
3620 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3622 LOGE("failed to get pad from first element");
3626 /* create ghostpad */
3627 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3628 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3629 LOGE("failed to add ghostpad to videobin");
3632 gst_object_unref(pad);
3634 /* done. free allocated variables */
3635 g_list_free(element_bucket);
3639 return MM_ERROR_NONE;
3642 LOGE("ERROR : releasing videobin");
3643 g_list_free(element_bucket);
3646 gst_object_unref(GST_OBJECT(pad));
3648 /* release videobin with it's childs */
3649 if (videobin[MMPLAYER_V_BIN].gst)
3650 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3652 MMPLAYER_FREEIF(videobin);
3653 player->pipeline->videobin = NULL;
3655 return MM_ERROR_PLAYER_INTERNAL;
3659 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3661 GList *element_bucket = NULL;
3662 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3664 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3665 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3666 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3667 "signal-handoffs", FALSE,
3670 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3671 _mmplayer_add_signal_connection(player,
3672 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3673 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3675 G_CALLBACK(__mmplayer_update_subtitle),
3678 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3679 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3681 if (!player->play_subtitle) {
3682 LOGD("add textbin sink as sink element of whole pipeline.");
3683 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3686 /* adding created elements to bin */
3687 LOGD("adding created elements to bin");
3688 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3689 LOGE("failed to add elements");
3693 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3694 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3695 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3697 /* linking elements in the bucket by added order. */
3698 LOGD("Linking elements in the bucket by added order.");
3699 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3700 LOGE("failed to link elements");
3704 /* done. free allocated variables */
3705 g_list_free(element_bucket);
3707 if (textbin[MMPLAYER_T_QUEUE].gst) {
3709 GstPad *ghostpad = NULL;
3711 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3713 LOGE("failed to get sink pad of text queue");
3717 ghostpad = gst_ghost_pad_new("text_sink", pad);
3718 gst_object_unref(pad);
3721 LOGE("failed to create ghostpad of textbin");
3725 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3726 LOGE("failed to add ghostpad to textbin");
3727 gst_object_unref(ghostpad);
3732 return MM_ERROR_NONE;
3735 g_list_free(element_bucket);
3737 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3738 LOGE("remove textbin sink from sink list");
3739 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3742 /* release element at __mmplayer_gst_create_text_sink_bin */
3743 return MM_ERROR_PLAYER_INTERNAL;
3747 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3749 mmplayer_gst_element_t *textbin = NULL;
3750 GList *element_bucket = NULL;
3751 int surface_type = 0;
3756 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3759 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3761 LOGE("failed to allocate memory for textbin");
3762 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3766 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3767 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3768 if (!textbin[MMPLAYER_T_BIN].gst) {
3769 LOGE("failed to create textbin");
3774 player->pipeline->textbin = textbin;
3777 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3778 LOGD("surface type for subtitle : %d", surface_type);
3779 switch (surface_type) {
3780 case MM_DISPLAY_SURFACE_OVERLAY:
3781 case MM_DISPLAY_SURFACE_NULL:
3782 case MM_DISPLAY_SURFACE_REMOTE:
3783 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3784 LOGE("failed to make plain text elements");
3795 return MM_ERROR_NONE;
3799 LOGD("ERROR : releasing textbin");
3801 g_list_free(element_bucket);
3803 /* release signal */
3804 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3806 /* release element which are not added to bin */
3807 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3808 /* NOTE : skip bin */
3809 if (textbin[i].gst) {
3810 GstObject *parent = NULL;
3811 parent = gst_element_get_parent(textbin[i].gst);
3814 gst_object_unref(GST_OBJECT(textbin[i].gst));
3815 textbin[i].gst = NULL;
3817 gst_object_unref(GST_OBJECT(parent));
3822 /* release textbin with it's childs */
3823 if (textbin[MMPLAYER_T_BIN].gst)
3824 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3826 MMPLAYER_FREEIF(textbin);
3827 player->pipeline->textbin = NULL;
3830 return MM_ERROR_PLAYER_INTERNAL;
3834 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3836 mmplayer_gst_element_t *mainbin = NULL;
3837 mmplayer_gst_element_t *textbin = NULL;
3838 MMHandleType attrs = 0;
3839 GstElement *subsrc = NULL;
3840 GstElement *subparse = NULL;
3841 gchar *subtitle_uri = NULL;
3842 const gchar *charset = NULL;
3848 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3850 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3852 mainbin = player->pipeline->mainbin;
3854 attrs = MMPLAYER_GET_ATTRS(player);
3856 LOGE("cannot get content attribute");
3857 return MM_ERROR_PLAYER_INTERNAL;
3860 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3861 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3862 LOGE("subtitle uri is not proper filepath.");
3863 return MM_ERROR_PLAYER_INVALID_URI;
3866 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3867 LOGE("failed to get storage info of subtitle path");
3868 return MM_ERROR_PLAYER_INVALID_URI;
3871 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3873 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3874 player->subtitle_language_list = NULL;
3875 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3877 /* create the subtitle source */
3878 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3880 LOGE("failed to create filesrc element");
3883 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3885 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3886 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3888 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3889 LOGW("failed to add queue");
3890 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3891 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3892 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3897 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3899 LOGE("failed to create subparse element");
3903 charset = _mmplayer_get_charset(subtitle_uri);
3905 LOGD("detected charset is %s", charset);
3906 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3909 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3910 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3912 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3913 LOGW("failed to add subparse");
3914 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3915 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3916 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3920 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3921 LOGW("failed to link subsrc and subparse");
3925 player->play_subtitle = TRUE;
3926 player->adjust_subtitle_pos = 0;
3928 LOGD("play subtitle using subtitle file");
3930 if (player->pipeline->textbin == NULL) {
3931 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3932 LOGE("failed to create text sink bin. continuing without text");
3936 textbin = player->pipeline->textbin;
3938 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3939 LOGW("failed to add textbin");
3941 /* release signal */
3942 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3944 /* release textbin with it's childs */
3945 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3946 MMPLAYER_FREEIF(player->pipeline->textbin);
3947 player->pipeline->textbin = textbin = NULL;
3951 LOGD("link text input selector and textbin ghost pad");
3953 player->textsink_linked = 1;
3954 player->external_text_idx = 0;
3955 LOGI("textsink is linked");
3957 textbin = player->pipeline->textbin;
3958 LOGD("text bin has been created. reuse it.");
3959 player->external_text_idx = 1;
3962 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3963 LOGW("failed to link subparse and textbin");
3967 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3969 LOGE("failed to get sink pad from textsink to probe data");
3973 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3974 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3976 gst_object_unref(pad);
3979 /* create dot. for debugging */
3980 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3983 return MM_ERROR_NONE;
3986 /* release text pipeline resource */
3987 player->textsink_linked = 0;
3989 /* release signal */
3990 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3992 if (player->pipeline->textbin) {
3993 LOGE("remove textbin");
3995 /* release textbin with it's childs */
3996 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3997 MMPLAYER_FREEIF(player->pipeline->textbin);
3998 player->pipeline->textbin = NULL;
4002 /* release subtitle elem */
4003 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4004 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4006 return MM_ERROR_PLAYER_INTERNAL;
4010 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4012 mmplayer_t *player = (mmplayer_t *)data;
4013 MMMessageParamType msg = {0, };
4014 GstClockTime duration = 0;
4015 gpointer text = NULL;
4016 guint text_size = 0;
4017 gboolean ret = TRUE;
4018 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4022 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4023 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4025 if (player->is_subtitle_force_drop) {
4026 LOGW("subtitle is dropped forcedly.");
4030 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4031 text = mapinfo.data;
4032 text_size = mapinfo.size;
4034 if (player->set_mode.subtitle_off) {
4035 LOGD("subtitle is OFF.");
4039 if (!text || (text_size == 0)) {
4040 LOGD("There is no subtitle to be displayed.");
4044 msg.data = (void *)text;
4046 duration = GST_BUFFER_DURATION(buffer);
4048 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4049 if (player->duration > GST_BUFFER_PTS(buffer))
4050 duration = player->duration - GST_BUFFER_PTS(buffer);
4053 LOGI("subtitle duration is invalid, subtitle duration change "
4054 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4056 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4058 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4060 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4061 gst_buffer_unmap(buffer, &mapinfo);
4068 static GstPadProbeReturn
4069 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4071 mmplayer_t *player = (mmplayer_t *)u_data;
4072 GstClockTime cur_timestamp = 0;
4073 gint64 adjusted_timestamp = 0;
4074 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4076 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4078 if (player->set_mode.subtitle_off) {
4079 LOGD("subtitle is OFF.");
4083 if (player->adjust_subtitle_pos == 0) {
4084 LOGD("nothing to do");
4088 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4089 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4091 if (adjusted_timestamp < 0) {
4092 LOGD("adjusted_timestamp under zero");
4097 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4098 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4099 GST_TIME_ARGS(cur_timestamp),
4100 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4102 return GST_PAD_PROBE_OK;
4106 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4110 /* check player and subtitlebin are created */
4111 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4112 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4114 if (position == 0) {
4115 LOGD("nothing to do");
4117 return MM_ERROR_NONE;
4120 /* check current postion */
4121 player->adjust_subtitle_pos = position;
4123 LOGD("save adjust_subtitle_pos in player");
4127 return MM_ERROR_NONE;
4131 * This function is to create audio or video pipeline for playing.
4133 * @param player [in] handle of player
4135 * @return This function returns zero on success.
4140 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4142 int ret = MM_ERROR_NONE;
4143 mmplayer_gst_element_t *mainbin = NULL;
4144 MMHandleType attrs = 0;
4147 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4149 /* get profile attribute */
4150 attrs = MMPLAYER_GET_ATTRS(player);
4152 LOGE("failed to get content attribute");
4156 /* create pipeline handles */
4157 if (player->pipeline) {
4158 LOGE("pipeline should be released before create new one");
4162 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4164 /* create mainbin */
4165 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4166 if (mainbin == NULL)
4169 /* create pipeline */
4170 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4171 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4172 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4173 LOGE("failed to create pipeline");
4178 player->pipeline->mainbin = mainbin;
4180 /* create the source and decoder elements */
4181 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4182 ret = _mmplayer_gst_build_es_pipeline(player);
4184 if (player->ini.use_uridecodebin3)
4185 ret = _mmplayer_gst_build_pipeline_with_src(player);
4187 ret = _mmplayer_gst_build_pipeline(player);
4190 if (ret != MM_ERROR_NONE) {
4191 LOGE("failed to create some elements");
4195 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4196 if (__mmplayer_check_subtitle(player)
4197 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4198 LOGE("failed to create text pipeline");
4201 ret = _mmplayer_gst_add_bus_watch(player);
4202 if (ret != MM_ERROR_NONE) {
4203 LOGE("failed to add bus watch");
4208 return MM_ERROR_NONE;
4211 _mmplayer_bus_watcher_remove(player);
4212 __mmplayer_gst_destroy_pipeline(player);
4213 return MM_ERROR_PLAYER_INTERNAL;
4217 __mmplayer_reset_gapless_state(mmplayer_t *player)
4220 MMPLAYER_RETURN_IF_FAIL(player
4222 && player->pipeline->audiobin
4223 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4225 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4232 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4235 int ret = MM_ERROR_NONE;
4239 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4241 /* cleanup stuffs */
4242 MMPLAYER_FREEIF(player->type);
4243 player->no_more_pad = FALSE;
4244 player->num_dynamic_pad = 0;
4246 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4247 player->subtitle_language_list = NULL;
4248 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4250 MMPLAYER_RECONFIGURE_LOCK(player);
4251 __mmplayer_reset_gapless_state(player);
4252 MMPLAYER_RECONFIGURE_UNLOCK(player);
4254 if (player->streamer) {
4255 _mm_player_streaming_initialize(player->streamer, FALSE);
4256 _mm_player_streaming_destroy(player->streamer);
4257 player->streamer = NULL;
4260 /* cleanup unlinked mime type */
4261 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4262 MMPLAYER_FREEIF(player->unlinked_video_mime);
4263 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4265 /* cleanup running stuffs */
4266 _mmplayer_cancel_eos_timer(player);
4268 /* cleanup gst stuffs */
4269 if (player->pipeline) {
4270 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4271 GstTagList *tag_list = player->pipeline->tag_list;
4273 /* first we need to disconnect all signal hander */
4274 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4277 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4278 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4279 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4280 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4281 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4282 gst_object_unref(bus);
4284 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4285 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4286 if (ret != MM_ERROR_NONE) {
4287 LOGE("fail to change state to NULL");
4288 return MM_ERROR_PLAYER_INTERNAL;
4291 LOGW("succeeded in changing state to NULL");
4293 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4296 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4297 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4299 /* free avsysaudiosink
4300 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4301 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4303 MMPLAYER_FREEIF(audiobin);
4304 MMPLAYER_FREEIF(videobin);
4305 MMPLAYER_FREEIF(textbin);
4306 MMPLAYER_FREEIF(mainbin);
4310 gst_tag_list_unref(tag_list);
4312 MMPLAYER_FREEIF(player->pipeline);
4314 MMPLAYER_FREEIF(player->album_art);
4316 if (player->v_stream_caps) {
4317 gst_caps_unref(player->v_stream_caps);
4318 player->v_stream_caps = NULL;
4321 if (player->a_stream_caps) {
4322 gst_caps_unref(player->a_stream_caps);
4323 player->a_stream_caps = NULL;
4326 if (player->s_stream_caps) {
4327 gst_caps_unref(player->s_stream_caps);
4328 player->s_stream_caps = NULL;
4330 _mmplayer_track_destroy(player);
4332 if (player->sink_elements)
4333 g_list_free(player->sink_elements);
4334 player->sink_elements = NULL;
4336 if (player->bufmgr) {
4337 tbm_bufmgr_deinit(player->bufmgr);
4338 player->bufmgr = NULL;
4341 LOGW("finished destroy pipeline");
4349 __mmplayer_gst_realize(mmplayer_t *player)
4352 int ret = MM_ERROR_NONE;
4356 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4358 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4360 ret = __mmplayer_gst_create_pipeline(player);
4362 LOGE("failed to create pipeline");
4366 /* set pipeline state to READY */
4367 /* NOTE : state change to READY must be performed sync. */
4368 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4369 ret = _mmplayer_gst_set_state(player,
4370 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4372 if (ret != MM_ERROR_NONE) {
4373 /* return error if failed to set state */
4374 LOGE("failed to set READY state");
4378 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4380 /* create dot before error-return. for debugging */
4381 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4389 __mmplayer_gst_unrealize(mmplayer_t *player)
4391 int ret = MM_ERROR_NONE;
4395 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4397 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4398 MMPLAYER_PRINT_STATE(player);
4400 /* release miscellaneous information */
4401 __mmplayer_release_misc(player);
4403 /* destroy pipeline */
4404 ret = __mmplayer_gst_destroy_pipeline(player);
4405 if (ret != MM_ERROR_NONE) {
4406 LOGE("failed to destory pipeline");
4410 /* release miscellaneous information.
4411 these info needs to be released after pipeline is destroyed. */
4412 __mmplayer_release_misc_post(player);
4414 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4422 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4427 LOGW("set_message_callback is called with invalid player handle");
4428 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4431 player->msg_cb = callback;
4432 player->msg_cb_param = user_param;
4434 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4438 return MM_ERROR_NONE;
4442 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4444 int ret = MM_ERROR_NONE;
4449 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4450 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4451 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4453 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4455 if (strstr(uri, "es_buff://")) {
4456 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4457 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4458 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4459 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4461 tmp = g_ascii_strdown(uri, strlen(uri));
4462 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4463 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4465 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4467 } else if (strstr(uri, "mms://")) {
4468 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4469 } else if ((path = strstr(uri, "mem://"))) {
4470 ret = __mmplayer_set_mem_uri(data, path, param);
4472 ret = __mmplayer_set_file_uri(data, uri);
4475 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4476 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4477 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4478 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4480 /* dump parse result */
4481 SECURE_LOGW("incoming uri : %s", uri);
4482 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4483 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4491 __mmplayer_can_do_interrupt(mmplayer_t *player)
4493 if (!player || !player->pipeline || !player->attrs) {
4494 LOGW("not initialized");
4498 if (player->audio_decoded_cb) {
4499 LOGW("not support in pcm extraction mode");
4503 /* check if seeking */
4504 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4505 MMMessageParamType msg_param;
4506 memset(&msg_param, 0, sizeof(MMMessageParamType));
4507 msg_param.code = MM_ERROR_PLAYER_SEEK;
4508 player->seek_state = MMPLAYER_SEEK_NONE;
4509 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4513 /* check other thread */
4514 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4515 LOGW("locked already, cmd state : %d", player->cmd);
4517 /* check application command */
4518 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4519 LOGW("playing.. should wait cmd lock then, will be interrupted");
4521 /* lock will be released at mrp_resource_release_cb() */
4522 MMPLAYER_CMD_LOCK(player);
4525 LOGW("nothing to do");
4528 LOGW("can interrupt immediately");
4532 FAILED: /* with CMD UNLOCKED */
4535 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4540 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4543 mmplayer_t *player = NULL;
4544 MMMessageParamType msg = {0, };
4546 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4551 LOGE("user_data is null");
4554 player = (mmplayer_t *)user_data;
4556 if (!__mmplayer_can_do_interrupt(player)) {
4557 LOGW("no need to interrupt, so leave");
4558 /* FIXME: there is no way to avoid releasing resource. */
4562 player->interrupted_by_resource = TRUE;
4564 /* get last play position */
4565 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4566 msg.union_type = MM_MSG_UNION_TIME;
4567 msg.time.elapsed = pos;
4568 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4570 LOGW("failed to get play position.");
4573 LOGD("video resource conflict so, resource will be freed by unrealizing");
4574 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4575 LOGE("failed to unrealize");
4577 /* lock is called in __mmplayer_can_do_interrupt() */
4578 MMPLAYER_CMD_UNLOCK(player);
4580 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4581 player->hw_resource[res_idx] = NULL;
4585 return TRUE; /* release all the resources */
4589 __mmplayer_initialize_video_roi(mmplayer_t *player)
4591 player->video_roi.scale_x = 0.0;
4592 player->video_roi.scale_y = 0.0;
4593 player->video_roi.scale_width = 1.0;
4594 player->video_roi.scale_height = 1.0;
4598 _mmplayer_create_player(MMHandleType handle)
4600 int ret = MM_ERROR_PLAYER_INTERNAL;
4601 bool enabled = false;
4603 mmplayer_t *player = MM_PLAYER_CAST(handle);
4607 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4609 /* initialize player state */
4610 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4611 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4612 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4613 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4615 /* check current state */
4616 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4618 /* construct attributes */
4619 player->attrs = _mmplayer_construct_attribute(handle);
4621 if (!player->attrs) {
4622 LOGE("Failed to construct attributes");
4626 /* initialize gstreamer with configured parameter */
4627 if (!__mmplayer_init_gstreamer(player)) {
4628 LOGE("Initializing gstreamer failed");
4629 _mmplayer_deconstruct_attribute(handle);
4633 /* create lock. note that g_tread_init() has already called in gst_init() */
4634 g_mutex_init(&player->fsink_lock);
4636 /* create update tag lock */
4637 g_mutex_init(&player->update_tag_lock);
4639 /* create gapless play mutex */
4640 g_mutex_init(&player->gapless_play_thread_mutex);
4642 /* create gapless play cond */
4643 g_cond_init(&player->gapless_play_thread_cond);
4645 /* create gapless play thread */
4646 player->gapless_play_thread =
4647 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4648 if (!player->gapless_play_thread) {
4649 LOGE("failed to create gapless play thread");
4650 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4651 g_mutex_clear(&player->gapless_play_thread_mutex);
4652 g_cond_clear(&player->gapless_play_thread_cond);
4656 player->bus_msg_q = g_queue_new();
4657 if (!player->bus_msg_q) {
4658 LOGE("failed to create queue for bus_msg");
4659 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4663 ret = _mmplayer_initialize_video_capture(player);
4664 if (ret != MM_ERROR_NONE) {
4665 LOGE("failed to initialize video capture");
4669 /* initialize resource manager */
4670 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4671 __resource_release_cb, player, &player->resource_manager)
4672 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4673 LOGE("failed to initialize resource manager");
4674 ret = MM_ERROR_PLAYER_INTERNAL;
4678 /* create video bo lock and cond */
4679 g_mutex_init(&player->video_bo_mutex);
4680 g_cond_init(&player->video_bo_cond);
4682 /* create subtitle info lock and cond */
4683 g_mutex_init(&player->subtitle_info_mutex);
4684 g_cond_init(&player->subtitle_info_cond);
4686 player->streaming_type = STREAMING_SERVICE_NONE;
4688 /* give default value of audio effect setting */
4689 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4690 player->sound.rg_enable = false;
4691 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4693 player->play_subtitle = FALSE;
4694 player->has_closed_caption = FALSE;
4695 player->pending_resume = FALSE;
4696 if (player->ini.dump_element_keyword[0][0] == '\0')
4697 player->ini.set_dump_element_flag = FALSE;
4699 player->ini.set_dump_element_flag = TRUE;
4701 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4702 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4703 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4705 /* Set video360 settings to their defaults for just-created player.
4708 player->is_360_feature_enabled = FALSE;
4709 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4710 LOGI("spherical feature info: %d", enabled);
4712 player->is_360_feature_enabled = TRUE;
4714 LOGE("failed to get spherical feature info");
4717 player->is_content_spherical = FALSE;
4718 player->is_video360_enabled = TRUE;
4719 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4720 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4721 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4722 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4723 player->video360_zoom = 1.0f;
4724 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4725 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4727 __mmplayer_initialize_video_roi(player);
4729 /* set player state to null */
4730 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4731 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4735 return MM_ERROR_NONE;
4739 g_mutex_clear(&player->fsink_lock);
4740 /* free update tag lock */
4741 g_mutex_clear(&player->update_tag_lock);
4742 g_queue_free(player->bus_msg_q);
4743 player->bus_msg_q = NULL;
4744 /* free gapless play thread */
4745 if (player->gapless_play_thread) {
4746 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4747 player->gapless_play_thread_exit = TRUE;
4748 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4749 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4751 g_thread_join(player->gapless_play_thread);
4752 player->gapless_play_thread = NULL;
4754 g_mutex_clear(&player->gapless_play_thread_mutex);
4755 g_cond_clear(&player->gapless_play_thread_cond);
4758 /* release attributes */
4759 _mmplayer_deconstruct_attribute(handle);
4767 __mmplayer_init_gstreamer(mmplayer_t *player)
4769 static gboolean initialized = FALSE;
4770 static const int max_argc = 50;
4772 gchar **argv = NULL;
4773 gchar **argv2 = NULL;
4779 LOGD("gstreamer already initialized.");
4784 argc = malloc(sizeof(int));
4785 argv = malloc(sizeof(gchar *) * max_argc);
4786 argv2 = malloc(sizeof(gchar *) * max_argc);
4788 if (!argc || !argv || !argv2)
4791 memset(argv, 0, sizeof(gchar *) * max_argc);
4792 memset(argv2, 0, sizeof(gchar *) * max_argc);
4796 argv[0] = g_strdup("mmplayer");
4799 for (i = 0; i < 5; i++) {
4800 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4801 if (strlen(player->ini.gst_param[i]) > 0) {
4802 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4807 /* we would not do fork for scanning plugins */
4808 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4811 /* check disable registry scan */
4812 if (player->ini.skip_rescan) {
4813 argv[*argc] = g_strdup("--gst-disable-registry-update");
4817 /* check disable segtrap */
4818 if (player->ini.disable_segtrap) {
4819 argv[*argc] = g_strdup("--gst-disable-segtrap");
4823 LOGD("initializing gstreamer with following parameter");
4824 LOGD("argc : %d", *argc);
4827 for (i = 0; i < arg_count; i++) {
4829 LOGD("argv[%d] : %s", i, argv2[i]);
4832 /* initializing gstreamer */
4833 if (!gst_init_check(argc, &argv, &err)) {
4834 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4841 for (i = 0; i < arg_count; i++) {
4843 LOGD("release - argv[%d] : %s", i, argv2[i]);
4845 MMPLAYER_FREEIF(argv2[i]);
4848 MMPLAYER_FREEIF(argv);
4849 MMPLAYER_FREEIF(argv2);
4850 MMPLAYER_FREEIF(argc);
4860 for (i = 0; i < arg_count; i++) {
4861 LOGD("free[%d] : %s", i, argv2[i]);
4862 MMPLAYER_FREEIF(argv2[i]);
4865 MMPLAYER_FREEIF(argv);
4866 MMPLAYER_FREEIF(argv2);
4867 MMPLAYER_FREEIF(argc);
4873 __mmplayer_check_async_state_transition(mmplayer_t *player)
4875 GstState element_state = GST_STATE_VOID_PENDING;
4876 GstState element_pending_state = GST_STATE_VOID_PENDING;
4877 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4878 GstElement *element = NULL;
4879 gboolean async = FALSE;
4881 /* check player handle */
4882 MMPLAYER_RETURN_IF_FAIL(player &&
4884 player->pipeline->mainbin &&
4885 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4888 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4890 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4891 LOGD("don't need to check the pipeline state");
4895 MMPLAYER_PRINT_STATE(player);
4897 /* wait for state transition */
4898 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4899 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4901 if (ret == GST_STATE_CHANGE_FAILURE) {
4902 LOGE(" [%s] state : %s pending : %s",
4903 GST_ELEMENT_NAME(element),
4904 gst_element_state_get_name(element_state),
4905 gst_element_state_get_name(element_pending_state));
4907 /* dump state of all element */
4908 _mmplayer_dump_pipeline_state(player);
4913 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4918 _mmplayer_destroy(MMHandleType handle)
4920 mmplayer_t *player = MM_PLAYER_CAST(handle);
4924 /* check player handle */
4925 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4927 /* destroy can called at anytime */
4928 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4930 /* check async state transition */
4931 __mmplayer_check_async_state_transition(player);
4933 /* release gapless play thread */
4934 if (player->gapless_play_thread) {
4935 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4936 player->gapless_play_thread_exit = TRUE;
4937 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4938 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4940 LOGD("waitting for gapless play thread exit");
4941 g_thread_join(player->gapless_play_thread);
4942 g_mutex_clear(&player->gapless_play_thread_mutex);
4943 g_cond_clear(&player->gapless_play_thread_cond);
4944 LOGD("gapless play thread released");
4947 _mmplayer_release_video_capture(player);
4949 /* de-initialize resource manager */
4950 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4951 player->resource_manager))
4952 LOGE("failed to deinitialize resource manager");
4954 /* release miscellaneous information */
4955 __mmplayer_release_misc(player);
4957 /* release pipeline */
4958 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4959 LOGE("failed to destory pipeline");
4960 return MM_ERROR_PLAYER_INTERNAL;
4963 g_queue_free(player->bus_msg_q);
4965 /* release subtitle info lock and cond */
4966 g_mutex_clear(&player->subtitle_info_mutex);
4967 g_cond_clear(&player->subtitle_info_cond);
4969 __mmplayer_release_dump_list(player->dump_list);
4971 /* release miscellaneous information.
4972 these info needs to be released after pipeline is destroyed. */
4973 __mmplayer_release_misc_post(player);
4975 /* release attributes */
4976 _mmplayer_deconstruct_attribute(handle);
4978 if (player->uri_info.uri_list) {
4979 GList *uri_list = player->uri_info.uri_list;
4980 for (; uri_list; uri_list = g_list_next(uri_list)) {
4981 gchar *uri = uri_list->data;
4982 MMPLAYER_FREEIF(uri);
4984 g_list_free(player->uri_info.uri_list);
4985 player->uri_info.uri_list = NULL;
4989 g_mutex_clear(&player->fsink_lock);
4992 g_mutex_clear(&player->update_tag_lock);
4994 /* release video bo lock and cond */
4995 g_mutex_clear(&player->video_bo_mutex);
4996 g_cond_clear(&player->video_bo_cond);
5000 return MM_ERROR_NONE;
5004 _mmplayer_realize(MMHandleType hplayer)
5006 mmplayer_t *player = (mmplayer_t *)hplayer;
5007 int ret = MM_ERROR_NONE;
5010 MMHandleType attrs = 0;
5011 int video_codec_type = 0;
5012 int audio_codec_type = 0;
5013 int default_codec_type = 0;
5016 /* check player handle */
5017 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5019 /* check current state */
5020 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5022 attrs = MMPLAYER_GET_ATTRS(player);
5024 LOGE("fail to get attributes.");
5025 return MM_ERROR_PLAYER_INTERNAL;
5027 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5028 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5030 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5031 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5033 if (ret != MM_ERROR_NONE) {
5034 LOGE("failed to parse profile");
5039 if (uri && (strstr(uri, "es_buff://"))) {
5040 if (strstr(uri, "es_buff://push_mode"))
5041 player->es_player_push_mode = TRUE;
5043 player->es_player_push_mode = FALSE;
5046 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5047 LOGW("mms protocol is not supported format.");
5048 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5051 if (MMPLAYER_IS_STREAMING(player))
5052 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5054 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5056 player->smooth_streaming = FALSE;
5057 player->videodec_linked = 0;
5058 player->audiodec_linked = 0;
5059 player->textsink_linked = 0;
5060 player->is_external_subtitle_present = FALSE;
5061 player->is_external_subtitle_added_now = FALSE;
5062 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5063 player->video360_metadata.is_spherical = -1;
5064 player->is_openal_plugin_used = FALSE;
5065 player->subtitle_language_list = NULL;
5066 player->is_subtitle_force_drop = FALSE;
5068 _mmplayer_track_initialize(player);
5069 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5071 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5072 gint prebuffer_ms = 0, rebuffer_ms = 0;
5074 player->streamer = _mm_player_streaming_create();
5075 _mm_player_streaming_initialize(player->streamer, TRUE);
5077 mm_attrs_multiple_get(player->attrs, NULL,
5078 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5079 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5081 if (prebuffer_ms > 0) {
5082 prebuffer_ms = MAX(prebuffer_ms, 1000);
5083 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5086 if (rebuffer_ms > 0) {
5087 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5088 rebuffer_ms = MAX(rebuffer_ms, 1000);
5089 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5092 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5093 player->streamer->buffering_req.rebuffer_time);
5096 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
5097 if (!strcmp(player->ini.audiocodec_default_type, "hw"))
5098 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
5100 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
5102 if (audio_codec_type != default_codec_type) {
5103 LOGD("audio dec sorting is required");
5104 player->need_audio_dec_sorting = TRUE;
5107 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
5108 if (video_codec_type != MM_PLAYER_CODEC_TYPE_DEFAULT) {
5109 LOGD("video dec sorting is required");
5110 player->need_video_dec_sorting = TRUE;
5113 /* realize pipeline */
5114 ret = __mmplayer_gst_realize(player);
5115 if (ret != MM_ERROR_NONE)
5116 LOGE("fail to realize the player.");
5118 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5126 _mmplayer_unrealize(MMHandleType hplayer)
5128 mmplayer_t *player = (mmplayer_t *)hplayer;
5129 int ret = MM_ERROR_NONE;
5133 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5135 MMPLAYER_CMD_UNLOCK(player);
5136 _mmplayer_bus_watcher_remove(player);
5137 /* destroy the gst bus msg thread which is created during realize.
5138 this funct have to be called before getting cmd lock. */
5139 _mmplayer_bus_msg_thread_destroy(player);
5140 MMPLAYER_CMD_LOCK(player);
5142 /* check current state */
5143 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5145 /* check async state transition */
5146 __mmplayer_check_async_state_transition(player);
5148 /* unrealize pipeline */
5149 ret = __mmplayer_gst_unrealize(player);
5151 if (!player->interrupted_by_resource) {
5152 int rm_ret = MM_ERROR_NONE;
5153 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5155 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5156 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5157 if (rm_ret != MM_ERROR_NONE)
5158 LOGE("failed to release [%d] resources", res_idx);
5167 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5169 mmplayer_t *player = (mmplayer_t *)hplayer;
5171 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5173 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5177 _mmplayer_get_state(MMHandleType hplayer, int *state)
5179 mmplayer_t *player = (mmplayer_t *)hplayer;
5181 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5183 *state = MMPLAYER_CURRENT_STATE(player);
5185 return MM_ERROR_NONE;
5189 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5191 GstElement *vol_element = NULL;
5192 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5195 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5196 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5198 /* check pipeline handle */
5199 if (!player->pipeline || !player->pipeline->audiobin) {
5200 LOGD("'%s' will be applied when audiobin is created", prop_name);
5202 /* NOTE : stored value will be used in create_audiobin
5203 * returning MM_ERROR_NONE here makes application to able to
5204 * set audio volume or mute at anytime.
5206 return MM_ERROR_NONE;
5209 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5210 volume_elem_id = MMPLAYER_A_SINK;
5212 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5214 LOGE("failed to get vol element %d", volume_elem_id);
5215 return MM_ERROR_PLAYER_INTERNAL;
5218 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5220 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5221 LOGE("there is no '%s' property", prop_name);
5222 return MM_ERROR_PLAYER_INTERNAL;
5225 if (!strcmp(prop_name, "volume")) {
5226 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5227 } else if (!strcmp(prop_name, "mute")) {
5228 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5230 LOGE("invalid property %s", prop_name);
5231 return MM_ERROR_PLAYER_INTERNAL;
5234 return MM_ERROR_NONE;
5238 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5240 int ret = MM_ERROR_NONE;
5241 mmplayer_t *player = (mmplayer_t *)hplayer;
5244 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5246 LOGD("volume = %f", volume);
5248 /* invalid factor range or not */
5249 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5250 LOGE("Invalid volume value");
5251 return MM_ERROR_INVALID_ARGUMENT;
5254 player->sound.volume = volume;
5256 ret = __mmplayer_gst_set_volume_property(player, "volume");
5263 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5265 mmplayer_t *player = (mmplayer_t *)hplayer;
5269 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5270 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5272 *volume = player->sound.volume;
5274 LOGD("current vol = %f", *volume);
5277 return MM_ERROR_NONE;
5281 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5283 int ret = MM_ERROR_NONE;
5284 mmplayer_t *player = (mmplayer_t *)hplayer;
5287 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5289 LOGD("mute = %d", mute);
5291 player->sound.mute = mute;
5293 ret = __mmplayer_gst_set_volume_property(player, "mute");
5300 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5302 mmplayer_t *player = (mmplayer_t *)hplayer;
5306 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5307 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5309 *mute = player->sound.mute;
5311 LOGD("current mute = %d", *mute);
5315 return MM_ERROR_NONE;
5319 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5321 mmplayer_t *player = (mmplayer_t *)hplayer;
5325 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5327 player->audio_stream_changed_cb = callback;
5328 player->audio_stream_changed_cb_user_param = user_param;
5329 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5333 return MM_ERROR_NONE;
5337 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5339 mmplayer_t *player = (mmplayer_t *)hplayer;
5343 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5345 player->audio_decoded_cb = callback;
5346 player->audio_decoded_cb_user_param = user_param;
5347 player->audio_extract_opt = opt;
5348 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5352 return MM_ERROR_NONE;
5356 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5358 mmplayer_t *player = (mmplayer_t *)hplayer;
5362 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5364 if (callback && !player->bufmgr)
5365 player->bufmgr = tbm_bufmgr_init(-1);
5367 player->set_mode.video_export = (callback) ? true : false;
5368 player->video_decoded_cb = callback;
5369 player->video_decoded_cb_user_param = user_param;
5371 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5375 return MM_ERROR_NONE;
5379 _mmplayer_start(MMHandleType hplayer)
5381 mmplayer_t *player = (mmplayer_t *)hplayer;
5382 gint ret = MM_ERROR_NONE;
5386 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5388 /* check current state */
5389 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5391 /* start pipeline */
5392 ret = _mmplayer_gst_start(player);
5393 if (ret != MM_ERROR_NONE)
5394 LOGE("failed to start player.");
5396 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5397 LOGD("force playing start even during buffering");
5398 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5406 /* NOTE: post "not supported codec message" to application
5407 * when one codec is not found during AUTOPLUGGING in MSL.
5408 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5409 * And, if any codec is not found, don't send message here.
5410 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5413 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5415 MMMessageParamType msg_param;
5416 memset(&msg_param, 0, sizeof(MMMessageParamType));
5417 gboolean post_msg_direct = FALSE;
5421 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5423 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5424 player->not_supported_codec, player->can_support_codec);
5426 if (player->not_found_demuxer) {
5427 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5428 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5430 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5431 MMPLAYER_FREEIF(msg_param.data);
5433 return MM_ERROR_NONE;
5436 if (player->not_supported_codec) {
5437 if (player->can_support_codec) {
5438 // There is one codec to play
5439 post_msg_direct = TRUE;
5441 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5442 post_msg_direct = TRUE;
5445 if (post_msg_direct) {
5446 MMMessageParamType msg_param;
5447 memset(&msg_param, 0, sizeof(MMMessageParamType));
5449 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5450 LOGW("not found AUDIO codec, posting error code to application.");
5452 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5453 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5454 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5455 LOGW("not found VIDEO codec, posting error code to application.");
5457 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5458 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5461 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5463 MMPLAYER_FREEIF(msg_param.data);
5465 return MM_ERROR_NONE;
5467 // no any supported codec case
5468 LOGW("not found any codec, posting error code to application.");
5470 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5471 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5472 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5474 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5475 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5478 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5480 MMPLAYER_FREEIF(msg_param.data);
5486 return MM_ERROR_NONE;
5489 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5491 GstState element_state = GST_STATE_VOID_PENDING;
5492 GstState element_pending_state = GST_STATE_VOID_PENDING;
5493 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5494 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5496 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5498 MMPLAYER_RECONFIGURE_LOCK(player);
5499 if (!player->gapless.reconfigure) {
5500 MMPLAYER_RECONFIGURE_UNLOCK(player);
5504 LOGI("reconfigure is under process");
5505 MMPLAYER_RECONFIGURE_WAIT(player);
5506 MMPLAYER_RECONFIGURE_UNLOCK(player);
5507 LOGI("reconfigure is completed.");
5509 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5510 &element_state, &element_pending_state, timeout * GST_SECOND);
5511 if (result == GST_STATE_CHANGE_FAILURE)
5512 LOGW("failed to get pipeline state in %d sec", timeout);
5517 /* NOTE : it should be able to call 'stop' anytime*/
5519 _mmplayer_stop(MMHandleType hplayer)
5521 mmplayer_t *player = (mmplayer_t *)hplayer;
5522 int ret = MM_ERROR_NONE;
5526 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5528 /* check current state */
5529 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5531 /* need to wait till the rebuilding pipeline is completed */
5532 __mmplayer_check_pipeline_reconfigure_state(player);
5533 MMPLAYER_RECONFIGURE_LOCK(player);
5534 __mmplayer_reset_gapless_state(player);
5535 MMPLAYER_RECONFIGURE_UNLOCK(player);
5537 /* NOTE : application should not wait for EOS after calling STOP */
5538 _mmplayer_cancel_eos_timer(player);
5541 player->seek_state = MMPLAYER_SEEK_NONE;
5544 ret = _mmplayer_gst_stop(player);
5546 if (ret != MM_ERROR_NONE)
5547 LOGE("failed to stop player.");
5555 _mmplayer_pause(MMHandleType hplayer)
5557 mmplayer_t *player = (mmplayer_t *)hplayer;
5558 gint64 pos_nsec = 0;
5559 gboolean async = FALSE;
5560 gint ret = MM_ERROR_NONE;
5564 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5566 /* check current state */
5567 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5569 /* check pipline reconfigure state */
5570 __mmplayer_check_pipeline_reconfigure_state(player);
5572 switch (MMPLAYER_CURRENT_STATE(player)) {
5573 case MM_PLAYER_STATE_READY:
5575 /* check prepare async or not.
5576 * In the case of streaming playback, it's recommned to avoid blocking wait.
5578 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5579 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5581 /* Changing back sync of rtspsrc to async */
5582 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5583 LOGD("async prepare working mode for rtsp");
5589 case MM_PLAYER_STATE_PLAYING:
5591 /* NOTE : store current point to overcome some bad operation
5592 *(returning zero when getting current position in paused state) of some
5595 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5596 LOGW("getting current position failed in paused");
5598 player->last_position = pos_nsec;
5600 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5601 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5602 This causes problem is position calculation during normal pause resume scenarios also.
5603 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5604 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5605 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5606 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5612 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5613 LOGD("doing async pause in case of ms buff src");
5617 /* pause pipeline */
5618 ret = _mmplayer_gst_pause(player, async);
5620 if (ret != MM_ERROR_NONE)
5621 LOGE("failed to pause player. ret : 0x%x", ret);
5623 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5624 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5625 LOGE("failed to update display_rotation");
5633 /* in case of streaming, pause could take long time.*/
5635 _mmplayer_abort_pause(MMHandleType hplayer)
5637 mmplayer_t *player = (mmplayer_t *)hplayer;
5638 int ret = MM_ERROR_NONE;
5642 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5644 player->pipeline->mainbin,
5645 MM_ERROR_PLAYER_NOT_INITIALIZED);
5647 LOGD("set the pipeline state to READY");
5649 /* set state to READY */
5650 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5651 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5652 if (ret != MM_ERROR_NONE) {
5653 LOGE("fail to change state to READY");
5654 return MM_ERROR_PLAYER_INTERNAL;
5657 LOGD("succeeded in changing state to READY");
5662 _mmplayer_resume(MMHandleType hplayer)
5664 mmplayer_t *player = (mmplayer_t *)hplayer;
5665 int ret = MM_ERROR_NONE;
5666 gboolean async = FALSE;
5670 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5672 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5673 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5674 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5678 /* Changing back sync mode rtspsrc to async */
5679 LOGD("async resume for rtsp case");
5683 /* check current state */
5684 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5686 ret = _mmplayer_gst_resume(player, async);
5687 if (ret != MM_ERROR_NONE)
5688 LOGE("failed to resume player.");
5690 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5691 LOGD("force resume even during buffering");
5692 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5701 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5703 mmplayer_t *player = (mmplayer_t *)hplayer;
5704 gint64 pos_nsec = 0;
5705 int ret = MM_ERROR_NONE;
5707 signed long long start = 0, stop = 0;
5708 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5711 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5712 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5714 /* The sound of video is not supported under 0.0 and over 2.0. */
5715 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5716 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5719 _mmplayer_set_mute(hplayer, mute);
5721 if (player->playback_rate == rate)
5722 return MM_ERROR_NONE;
5724 /* If the position is reached at start potion during fast backward, EOS is posted.
5725 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5727 player->playback_rate = rate;
5729 current_state = MMPLAYER_CURRENT_STATE(player);
5731 if (current_state != MM_PLAYER_STATE_PAUSED)
5732 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5734 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5736 if ((current_state == MM_PLAYER_STATE_PAUSED)
5737 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5738 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5739 pos_nsec = player->last_position;
5744 stop = GST_CLOCK_TIME_NONE;
5746 start = GST_CLOCK_TIME_NONE;
5750 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5751 player->playback_rate,
5753 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5754 GST_SEEK_TYPE_SET, start,
5755 GST_SEEK_TYPE_SET, stop)) {
5756 LOGE("failed to set speed playback");
5757 return MM_ERROR_PLAYER_SEEK;
5760 LOGD("succeeded to set speed playback as %0.1f", rate);
5764 return MM_ERROR_NONE;;
5768 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5770 mmplayer_t *player = (mmplayer_t *)hplayer;
5771 int ret = MM_ERROR_NONE;
5775 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5777 /* check pipline reconfigure state */
5778 __mmplayer_check_pipeline_reconfigure_state(player);
5780 ret = _mmplayer_gst_set_position(player, position, FALSE);
5788 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5790 mmplayer_t *player = (mmplayer_t *)hplayer;
5791 int ret = MM_ERROR_NONE;
5793 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5794 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5796 if (g_strrstr(player->type, "video/mpegts"))
5797 __mmplayer_update_duration_value(player);
5799 *duration = player->duration;
5804 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5806 mmplayer_t *player = (mmplayer_t *)hplayer;
5807 int ret = MM_ERROR_NONE;
5809 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5811 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5817 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5819 mmplayer_t *player = (mmplayer_t *)hplayer;
5820 int ret = MM_ERROR_NONE;
5824 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5826 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5834 __mmplayer_is_midi_type(gchar *str_caps)
5836 if ((g_strrstr(str_caps, "audio/midi")) ||
5837 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5838 (g_strrstr(str_caps, "application/x-smaf")) ||
5839 (g_strrstr(str_caps, "audio/x-imelody")) ||
5840 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5841 (g_strrstr(str_caps, "audio/xmf")) ||
5842 (g_strrstr(str_caps, "audio/mxmf"))) {
5851 __mmplayer_is_only_mp3_type(gchar *str_caps)
5853 if (g_strrstr(str_caps, "application/x-id3") ||
5854 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5860 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5862 GstStructure *caps_structure = NULL;
5863 gint samplerate = 0;
5867 MMPLAYER_RETURN_IF_FAIL(player && caps);
5869 caps_structure = gst_caps_get_structure(caps, 0);
5871 /* set stream information */
5872 gst_structure_get_int(caps_structure, "rate", &samplerate);
5873 gst_structure_get_int(caps_structure, "channels", &channels);
5875 mm_player_set_attribute((MMHandleType)player, NULL,
5876 "content_audio_samplerate", samplerate,
5877 "content_audio_channels", channels, NULL);
5879 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5883 __mmplayer_update_content_type_info(mmplayer_t *player)
5886 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5888 if (__mmplayer_is_midi_type(player->type)) {
5889 player->bypass_audio_effect = TRUE;
5893 if (!player->streamer) {
5894 LOGD("no need to check streaming type");
5898 if (g_strrstr(player->type, "application/x-hls")) {
5899 /* If it can't know exact type when it parses uri because of redirection case,
5900 * it will be fixed by typefinder or when doing autoplugging.
5902 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5903 player->streamer->is_adaptive_streaming = TRUE;
5904 } else if (g_strrstr(player->type, "application/dash+xml")) {
5905 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5906 player->streamer->is_adaptive_streaming = TRUE;
5909 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5910 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5911 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5913 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5914 if (player->streamer->is_adaptive_streaming)
5915 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5917 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5921 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5926 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5927 GstCaps *caps, gpointer data)
5929 mmplayer_t *player = (mmplayer_t *)data;
5933 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5935 /* store type string */
5936 MMPLAYER_FREEIF(player->type);
5937 player->type = gst_caps_to_string(caps);
5939 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5940 player, player->type, probability, gst_caps_get_size(caps));
5942 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5943 (g_strrstr(player->type, "audio/x-raw-int"))) {
5944 LOGE("not support media format");
5946 if (player->msg_posted == FALSE) {
5947 MMMessageParamType msg_param;
5948 memset(&msg_param, 0, sizeof(MMMessageParamType));
5950 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5951 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5953 /* don't post more if one was sent already */
5954 player->msg_posted = TRUE;
5959 __mmplayer_update_content_type_info(player);
5961 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
5964 pad = gst_element_get_static_pad(tf, "src");
5966 LOGE("fail to get typefind src pad.");
5970 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5971 gboolean async = FALSE;
5972 LOGE("failed to autoplug %s", player->type);
5974 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5976 if (async && player->msg_posted == FALSE)
5977 __mmplayer_handle_missed_plugin(player);
5979 gst_object_unref(GST_OBJECT(pad));
5986 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5988 GstElement *decodebin = NULL;
5992 /* create decodebin */
5993 decodebin = gst_element_factory_make("decodebin", NULL);
5996 LOGE("fail to create decodebin");
6000 /* raw pad handling signal */
6001 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6002 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6004 /* no-more-pad pad handling signal */
6005 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6006 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6008 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6009 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6011 /* This signal is emitted when a pad for which there is no further possible
6012 decoding is added to the decodebin.*/
6013 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6014 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6016 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6017 before looking for any elements that can handle that stream.*/
6018 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6019 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6021 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6022 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6023 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6025 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6026 before looking for any elements that can handle that stream.*/
6027 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6028 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6030 /* This signal is emitted once decodebin has finished decoding all the data.*/
6031 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6032 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6034 /* This signal is emitted when a element is added to the bin.*/
6035 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6036 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6043 __mmplayer_gst_make_queue2(mmplayer_t *player)
6045 GstElement *queue2 = NULL;
6046 gint64 dur_bytes = 0L;
6047 mmplayer_gst_element_t *mainbin = NULL;
6048 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6051 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6053 mainbin = player->pipeline->mainbin;
6055 queue2 = gst_element_factory_make("queue2", "queue2");
6057 LOGE("failed to create buffering queue element");
6061 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6062 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6064 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6066 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6067 * skip the pull mode(file or ring buffering) setting. */
6068 if (dur_bytes > 0) {
6069 if (!g_strrstr(player->type, "video/mpegts")) {
6070 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6071 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6077 _mm_player_streaming_set_queue2(player->streamer,
6081 (guint64)dur_bytes); /* no meaning at the moment */
6087 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6089 mmplayer_gst_element_t *mainbin = NULL;
6090 GstElement *decodebin = NULL;
6091 GstElement *queue2 = NULL;
6092 GstPad *sinkpad = NULL;
6093 GstPad *qsrcpad = NULL;
6096 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6098 mainbin = player->pipeline->mainbin;
6100 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6102 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6103 LOGW("need to check: muxed buffer is not null");
6106 queue2 = __mmplayer_gst_make_queue2(player);
6108 LOGE("failed to make queue2");
6112 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6113 LOGE("failed to add buffering queue");
6117 sinkpad = gst_element_get_static_pad(queue2, "sink");
6118 qsrcpad = gst_element_get_static_pad(queue2, "src");
6120 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6121 LOGE("failed to link [%s:%s]-[%s:%s]",
6122 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6126 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6127 LOGE("failed to sync queue2 state with parent");
6131 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6132 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6136 gst_object_unref(GST_OBJECT(sinkpad));
6140 /* create decodebin */
6141 decodebin = _mmplayer_gst_make_decodebin(player);
6143 LOGE("failed to make decodebin");
6147 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6148 LOGE("failed to add decodebin");
6152 /* to force caps on the decodebin element and avoid reparsing stuff by
6153 * typefind. It also avoids a deadlock in the way typefind activates pads in
6154 * the state change */
6155 g_object_set(decodebin, "sink-caps", caps, NULL);
6157 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6159 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6160 LOGE("failed to link [%s:%s]-[%s:%s]",
6161 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6165 gst_object_unref(GST_OBJECT(sinkpad));
6167 gst_object_unref(GST_OBJECT(qsrcpad));
6170 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6171 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6173 /* set decodebin property about buffer in streaming playback. *
6174 * in case of HLS/DASH, it does not need to have big buffer *
6175 * because it is kind of adaptive streaming. */
6176 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6177 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6178 gint high_percent = 0;
6180 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6181 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6183 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6185 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6187 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6188 "high-percent", high_percent,
6189 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6190 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6191 "max-size-buffers", 0, NULL); // disable or automatic
6194 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6195 LOGE("failed to sync decodebin state with parent");
6206 gst_object_unref(GST_OBJECT(sinkpad));
6209 gst_object_unref(GST_OBJECT(qsrcpad));
6212 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6213 * You need to explicitly set elements to the NULL state before
6214 * dropping the final reference, to allow them to clean up.
6216 gst_element_set_state(queue2, GST_STATE_NULL);
6218 /* And, it still has a parent "player".
6219 * You need to let the parent manage the object instead of unreffing the object directly.
6221 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6222 gst_object_unref(queue2);
6227 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6228 * You need to explicitly set elements to the NULL state before
6229 * dropping the final reference, to allow them to clean up.
6231 gst_element_set_state(decodebin, GST_STATE_NULL);
6233 /* And, it still has a parent "player".
6234 * You need to let the parent manage the object instead of unreffing the object directly.
6237 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6238 gst_object_unref(decodebin);
6246 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6250 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6251 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6253 LOGD("class : %s, mime : %s", factory_class, mime);
6255 /* add missing plugin */
6256 /* NOTE : msl should check missing plugin for image mime type.
6257 * Some motion jpeg clips can have playable audio track.
6258 * So, msl have to play audio after displaying popup written video format not supported.
6260 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6261 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6262 LOGD("not found demuxer");
6263 player->not_found_demuxer = TRUE;
6264 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6270 if (!g_strrstr(factory_class, "Demuxer")) {
6271 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6272 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6273 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6275 /* check that clip have multi tracks or not */
6276 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6277 LOGD("video plugin is already linked");
6279 LOGW("add VIDEO to missing plugin");
6280 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6281 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6283 } else if (g_str_has_prefix(mime, "audio")) {
6284 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6285 LOGD("audio plugin is already linked");
6287 LOGW("add AUDIO to missing plugin");
6288 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6289 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6297 return MM_ERROR_NONE;
6301 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6303 mmplayer_t *player = (mmplayer_t *)data;
6307 MMPLAYER_RETURN_IF_FAIL(player);
6309 /* remove fakesink. */
6310 if (!_mmplayer_gst_remove_fakesink(player,
6311 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6312 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6313 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6314 * source element are not same. To overcome this situation, this function will called
6315 * several places and several times. Therefore, this is not an error case.
6320 LOGD("[handle: %p] pipeline has completely constructed", player);
6322 if ((player->msg_posted == FALSE) &&
6323 (player->cmd >= MMPLAYER_COMMAND_START))
6324 __mmplayer_handle_missed_plugin(player);
6326 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6330 __mmplayer_check_profile(void)
6333 static int profile_tv = -1;
6335 if (__builtin_expect(profile_tv != -1, 1))
6338 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6339 switch (*profileName) {
6354 __mmplayer_get_next_uri(mmplayer_t *player)
6356 mmplayer_parse_profile_t profile;
6358 guint num_of_list = 0;
6361 num_of_list = g_list_length(player->uri_info.uri_list);
6362 uri_idx = player->uri_info.uri_idx;
6364 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6365 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6366 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6368 LOGW("next uri does not exist");
6372 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6373 LOGE("failed to parse profile");
6377 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6378 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6379 LOGW("uri type is not supported(%d)", profile.uri_type);
6383 LOGD("success to find next uri %d", uri_idx);
6387 if (!uri || uri_idx == num_of_list) {
6388 LOGE("failed to find next uri");
6392 player->uri_info.uri_idx = uri_idx;
6393 if (mm_player_set_attribute((MMHandleType)player, NULL,
6394 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6395 LOGE("failed to set attribute");
6399 SECURE_LOGD("next playback uri: %s", uri);
6404 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6406 #define REPEAT_COUNT_INFINITE -1
6407 #define REPEAT_COUNT_MIN 2
6408 #define ORIGINAL_URI_ONLY 1
6410 MMHandleType attrs = 0;
6414 guint num_of_uri = 0;
6415 int profile_tv = -1;
6419 LOGD("checking for gapless play option");
6421 if (player->build_audio_offload) {
6422 LOGE("offload path is not supportable.");
6426 if (player->pipeline->textbin) {
6427 LOGE("subtitle path is enabled. gapless play is not supported.");
6431 attrs = MMPLAYER_GET_ATTRS(player);
6433 LOGE("fail to get attributes.");
6437 mm_attrs_multiple_get(player->attrs, NULL,
6438 "content_video_found", &video,
6439 "profile_play_count", &count,
6440 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6442 /* gapless playback is not supported in case of video at TV profile. */
6443 profile_tv = __mmplayer_check_profile();
6444 if (profile_tv && video) {
6445 LOGW("not support video gapless playback");
6449 /* check repeat count in case of audio */
6451 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6452 LOGW("gapless is disabled");
6456 num_of_uri = g_list_length(player->uri_info.uri_list);
6458 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6460 if (num_of_uri == ORIGINAL_URI_ONLY) {
6461 /* audio looping path */
6462 if (count >= REPEAT_COUNT_MIN) {
6463 /* decrease play count */
6464 /* we succeeded to rewind. update play count and then wait for next EOS */
6466 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6467 } else if (count != REPEAT_COUNT_INFINITE) {
6468 LOGD("there is no next uri and no repeat");
6471 LOGD("looping cnt %d", count);
6473 /* gapless playback path */
6474 if (!__mmplayer_get_next_uri(player)) {
6475 LOGE("failed to get next uri");
6482 LOGE("unable to play gapless path. EOS will be posted soon");
6487 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6489 mmplayer_track_t *selector = &player->track[type];
6490 mmplayer_gst_element_t *sinkbin = NULL;
6491 main_element_id_e selectorId = MMPLAYER_M_NUM;
6492 main_element_id_e sinkId = MMPLAYER_M_NUM;
6493 GstPad *srcpad = NULL;
6494 GstPad *sinkpad = NULL;
6495 gboolean send_notice = FALSE;
6498 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6500 LOGD("type %d", type);
6503 case MM_PLAYER_TRACK_TYPE_AUDIO:
6504 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6505 sinkId = MMPLAYER_A_BIN;
6506 sinkbin = player->pipeline->audiobin;
6508 case MM_PLAYER_TRACK_TYPE_VIDEO:
6509 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6510 sinkId = MMPLAYER_V_BIN;
6511 sinkbin = player->pipeline->videobin;
6514 case MM_PLAYER_TRACK_TYPE_TEXT:
6515 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6516 sinkId = MMPLAYER_T_BIN;
6517 sinkbin = player->pipeline->textbin;
6520 LOGE("requested type is not supportable");
6525 if (player->pipeline->mainbin[selectorId].gst) {
6528 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6530 if (selector->event_probe_id != 0)
6531 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6532 selector->event_probe_id = 0;
6534 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6535 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6537 if (srcpad && sinkpad) {
6538 /* after getting drained signal there is no data flows, so no need to do pad_block */
6539 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6540 gst_pad_unlink(srcpad, sinkpad);
6542 /* send custom event to sink pad to handle it at video sink */
6544 LOGD("send custom event to sinkpad");
6545 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6546 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6547 gst_pad_send_event(sinkpad, event);
6551 gst_object_unref(sinkpad);
6554 gst_object_unref(srcpad);
6557 LOGD("selector release");
6559 /* release and unref requests pad from the selector */
6560 for (n = 0; n < selector->streams->len; n++) {
6561 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6562 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6565 g_ptr_array_set_size(selector->streams, 0);
6567 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6568 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6570 player->pipeline->mainbin[selectorId].gst = NULL;
6578 __mmplayer_deactivate_old_path(mmplayer_t *player)
6581 MMPLAYER_RETURN_IF_FAIL(player);
6583 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6584 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6585 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6586 LOGE("deactivate selector error");
6590 _mmplayer_track_destroy(player);
6591 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6593 if (player->streamer) {
6594 _mm_player_streaming_initialize(player->streamer, FALSE);
6595 _mm_player_streaming_destroy(player->streamer);
6596 player->streamer = NULL;
6599 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6605 if (!player->msg_posted) {
6606 MMMessageParamType msg = {0,};
6609 msg.code = MM_ERROR_PLAYER_INTERNAL;
6610 LOGE("gapless_uri_play> deactivate error");
6612 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6613 player->msg_posted = TRUE;
6619 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6621 int result = MM_ERROR_NONE;
6622 mmplayer_t *player = (mmplayer_t *)hplayer;
6625 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6626 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6628 if (mm_player_set_attribute(hplayer, NULL,
6629 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6630 LOGE("failed to set attribute");
6631 result = MM_ERROR_PLAYER_INTERNAL;
6633 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6634 LOGE("failed to add the original uri in the uri list.");
6642 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6644 mmplayer_t *player = (mmplayer_t *)hplayer;
6645 guint num_of_list = 0;
6649 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6650 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6652 if (player->pipeline && player->pipeline->textbin) {
6653 LOGE("subtitle path is enabled.");
6654 return MM_ERROR_PLAYER_INVALID_STATE;
6657 num_of_list = g_list_length(player->uri_info.uri_list);
6659 if (is_first_path) {
6660 if (num_of_list == 0) {
6661 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6662 SECURE_LOGD("add original path : %s", uri);
6664 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6665 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6667 SECURE_LOGD("change original path : %s", uri);
6670 MMHandleType attrs = 0;
6671 attrs = MMPLAYER_GET_ATTRS(player);
6673 if (num_of_list == 0) {
6674 char *original_uri = NULL;
6677 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6679 if (!original_uri) {
6680 LOGE("there is no original uri.");
6681 return MM_ERROR_PLAYER_INVALID_STATE;
6684 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6685 player->uri_info.uri_idx = 0;
6687 SECURE_LOGD("add original path at first : %s", original_uri);
6691 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6692 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6696 return MM_ERROR_NONE;
6700 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6702 mmplayer_t *player = (mmplayer_t *)hplayer;
6703 char *next_uri = NULL;
6704 guint num_of_list = 0;
6707 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6709 num_of_list = g_list_length(player->uri_info.uri_list);
6711 if (num_of_list > 0) {
6712 gint uri_idx = player->uri_info.uri_idx;
6714 if (uri_idx < num_of_list-1)
6719 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6720 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6722 *uri = g_strdup(next_uri);
6726 return MM_ERROR_NONE;
6730 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6731 GstCaps *caps, gpointer data)
6733 mmplayer_t *player = (mmplayer_t *)data;
6734 const gchar *klass = NULL;
6735 const gchar *mime = NULL;
6736 gchar *caps_str = NULL;
6738 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6739 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6740 caps_str = gst_caps_to_string(caps);
6742 LOGW("unknown type of caps : %s from %s",
6743 caps_str, GST_ELEMENT_NAME(elem));
6745 MMPLAYER_FREEIF(caps_str);
6747 /* There is no available codec. */
6748 __mmplayer_check_not_supported_codec(player, klass, mime);
6752 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6753 GstCaps *caps, gpointer data)
6755 mmplayer_t *player = (mmplayer_t *)data;
6756 const char *mime = NULL;
6757 gboolean ret = TRUE;
6759 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6760 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6762 if (g_str_has_prefix(mime, "audio")) {
6763 GstStructure *caps_structure = NULL;
6764 gint samplerate = 0;
6766 gchar *caps_str = NULL;
6768 caps_structure = gst_caps_get_structure(caps, 0);
6769 gst_structure_get_int(caps_structure, "rate", &samplerate);
6770 gst_structure_get_int(caps_structure, "channels", &channels);
6772 if ((channels > 0 && samplerate == 0)) {
6773 LOGD("exclude audio...");
6777 caps_str = gst_caps_to_string(caps);
6778 /* set it directly because not sent by TAG */
6779 if (g_strrstr(caps_str, "mobile-xmf"))
6780 mm_player_set_attribute((MMHandleType)player, NULL,
6781 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6783 MMPLAYER_FREEIF(caps_str);
6784 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6785 LOGD("already video linked");
6788 LOGD("found new stream");
6795 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6797 gboolean ret = FALSE;
6798 GDBusConnection *conn = NULL;
6800 GVariant *result = NULL;
6801 const gchar *dbus_device_type = NULL;
6802 const gchar *dbus_ret = NULL;
6805 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6807 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6812 result = g_dbus_connection_call_sync(conn,
6813 "org.pulseaudio.Server",
6814 "/org/pulseaudio/StreamManager",
6815 "org.pulseaudio.StreamManager",
6816 "GetCurrentMediaRoutingPath",
6817 g_variant_new("(s)", "out"),
6818 G_VARIANT_TYPE("(ss)"),
6819 G_DBUS_CALL_FLAGS_NONE,
6823 if (!result || err) {
6824 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6829 /* device type is listed in stream-map.json at mmfw-sysconf */
6830 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6832 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6833 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6836 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6837 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6838 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6839 LOGD("audio offload is supportable");
6845 LOGD("audio offload is not supportable");
6848 g_variant_unref(result);
6850 g_object_unref(conn);
6855 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6857 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6858 gint64 position = 0;
6860 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6861 player->pipeline && player->pipeline->mainbin);
6863 MMPLAYER_CMD_LOCK(player);
6864 current_state = MMPLAYER_CURRENT_STATE(player);
6866 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6867 LOGW("getting current position failed in paused");
6869 _mmplayer_unrealize((MMHandleType)player);
6870 _mmplayer_realize((MMHandleType)player);
6872 _mmplayer_set_position((MMHandleType)player, position);
6874 /* async not to be blocked in streaming case */
6875 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6877 _mmplayer_pause((MMHandleType)player);
6879 if (current_state == MM_PLAYER_STATE_PLAYING)
6880 _mmplayer_start((MMHandleType)player);
6881 MMPLAYER_CMD_UNLOCK(player);
6883 LOGD("rebuilding audio pipeline is completed.");
6886 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6888 mmplayer_t *player = (mmplayer_t *)user_data;
6889 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6890 gboolean is_supportable = FALSE;
6892 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6893 LOGW("failed to get device type");
6895 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6897 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6898 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6899 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6900 LOGD("ignore this dev connected info");
6904 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6905 if (player->build_audio_offload == is_supportable) {
6906 LOGD("keep current pipeline without re-building");
6910 /* rebuild pipeline */
6911 LOGD("re-build pipeline - offload: %d", is_supportable);
6912 player->build_audio_offload = FALSE;
6913 __mmplayer_rebuild_audio_pipeline(player);
6919 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6921 unsigned int id = 0;
6923 if (player->audio_device_cb_id != 0) {
6924 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6928 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6929 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6930 LOGD("added device connected cb (%u)", id);
6931 player->audio_device_cb_id = id;
6933 LOGW("failed to add device connected cb");
6940 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
6942 mmplayer_t *player = (mmplayer_t *)hplayer;
6945 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6946 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
6948 *activated = player->build_audio_offload;
6950 LOGD("offload activated : %d", (int)*activated);
6953 return MM_ERROR_NONE;
6957 __mmplayer_is_offload_supported_type(mmplayer_t *player)
6960 this function need to be updated according to the supported media format
6961 @see player->ini.audio_offload_media_format */
6963 if (__mmplayer_is_only_mp3_type(player->type)) {
6964 LOGD("offload supportable media format type");
6972 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6974 gboolean ret = FALSE;
6975 GstElementFactory *factory = NULL;
6978 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6980 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6981 if (!__mmplayer_is_offload_supported_type(player))
6984 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6985 LOGD("there is no audio offload sink");
6989 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6990 LOGW("there is no audio device type to support offload");
6994 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6996 LOGW("there is no installed audio offload sink element");
6999 gst_object_unref(factory);
7001 if (__mmplayer_acquire_hw_resource(player,
7002 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7003 LOGE("failed to acquire audio offload decoder resource");
7007 if (!__mmplayer_add_audio_device_connected_cb(player))
7010 if (!__mmplayer_is_audio_offload_device_type(player))
7013 LOGD("audio offload can be built");
7018 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7024 static GstAutoplugSelectResult
7025 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7027 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7028 int audio_offload = 0;
7030 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7031 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7033 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7034 LOGD("expose audio path to build offload output path");
7035 player->build_audio_offload = TRUE;
7036 /* update codec info */
7037 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7038 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7039 player->audiodec_linked = 1;
7041 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7045 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7046 And need to consider the multi-track audio content.
7047 There is no HW audio decoder in public. */
7049 /* set stream information */
7050 if (!player->audiodec_linked)
7051 __mmplayer_set_audio_attrs(player, caps);
7053 /* update codec info */
7054 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7055 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7056 player->audiodec_linked = 1;
7058 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7060 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7061 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7063 /* mark video decoder for acquire */
7064 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7065 LOGW("video decoder resource is already acquired, skip it.");
7066 ret = GST_AUTOPLUG_SELECT_SKIP;
7070 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7071 LOGE("failed to acquire video decoder resource");
7072 ret = GST_AUTOPLUG_SELECT_SKIP;
7075 player->interrupted_by_resource = FALSE;
7078 /* update codec info */
7079 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7080 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7081 player->videodec_linked = 1;
7089 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7090 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7092 #define DEFAULT_IDX 0xFFFF
7093 #define MIN_FACTORY_NUM 2
7094 mmplayer_t *player = (mmplayer_t *)data;
7095 GValueArray *new_factories = NULL;
7096 GValue val = { 0, };
7097 GstElementFactory *factory = NULL;
7098 const gchar *klass = NULL;
7099 gchar *factory_name = NULL;
7100 guint hw_dec_idx = DEFAULT_IDX;
7101 guint first_sw_dec_idx = DEFAULT_IDX;
7102 guint last_sw_dec_idx = DEFAULT_IDX;
7103 guint new_pos = DEFAULT_IDX;
7104 guint rm_pos = DEFAULT_IDX;
7105 int audio_codec_type;
7106 int video_codec_type;
7107 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7109 if (factories->n_values < MIN_FACTORY_NUM)
7112 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7113 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7116 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7118 for (int i = 0 ; i < factories->n_values ; i++) {
7119 gchar *hw_dec_info = NULL;
7120 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7122 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7124 LOGW("failed to get factory object");
7127 klass = gst_element_factory_get_klass(factory);
7128 factory_name = GST_OBJECT_NAME(factory);
7131 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7133 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7134 if (!player->need_audio_dec_sorting) {
7135 LOGD("sorting is not required");
7138 codec_type = audio_codec_type;
7139 hw_dec_info = player->ini.audiocodec_element_hw;
7140 sw_dec_info = player->ini.audiocodec_element_sw;
7141 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7142 if (!player->need_video_dec_sorting) {
7143 LOGD("sorting is not required");
7146 codec_type = video_codec_type;
7147 hw_dec_info = player->ini.videocodec_element_hw;
7148 sw_dec_info = player->ini.videocodec_element_sw;
7153 if (g_strrstr(factory_name, hw_dec_info)) {
7156 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7157 if (strstr(factory_name, sw_dec_info[j])) {
7158 last_sw_dec_idx = i;
7159 if (first_sw_dec_idx == DEFAULT_IDX) {
7160 first_sw_dec_idx = i;
7165 if (first_sw_dec_idx == DEFAULT_IDX)
7166 LOGW("unknown codec %s", factory_name);
7170 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7173 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7174 if (hw_dec_idx < first_sw_dec_idx)
7176 new_pos = first_sw_dec_idx;
7177 rm_pos = hw_dec_idx + 1;
7178 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7179 if (last_sw_dec_idx < hw_dec_idx)
7181 new_pos = last_sw_dec_idx + 1;
7182 rm_pos = hw_dec_idx;
7187 /* change position - insert H/W decoder according to the new position */
7188 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7190 LOGW("failed to get factory object");
7193 new_factories = g_value_array_copy(factories);
7194 g_value_init (&val, G_TYPE_OBJECT);
7195 g_value_set_object (&val, factory);
7196 g_value_array_insert(new_factories, new_pos, &val);
7197 g_value_unset (&val);
7198 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7200 for (int i = 0 ; i < new_factories->n_values ; i++) {
7201 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7203 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7204 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7206 LOGE("[Re-arranged] failed to get factory object");
7209 return new_factories;
7213 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7214 GstCaps *caps, GstElementFactory *factory, gpointer data)
7216 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7217 mmplayer_t *player = (mmplayer_t *)data;
7219 gchar *factory_name = NULL;
7220 gchar *caps_str = NULL;
7221 const gchar *klass = NULL;
7224 factory_name = GST_OBJECT_NAME(factory);
7225 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7226 caps_str = gst_caps_to_string(caps);
7228 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7230 /* store type string */
7231 if (player->type == NULL) {
7232 player->type = gst_caps_to_string(caps);
7233 __mmplayer_update_content_type_info(player);
7236 /* filtering exclude keyword */
7237 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7238 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7239 LOGW("skipping [%s] by exculde keyword [%s]",
7240 factory_name, player->ini.exclude_element_keyword[idx]);
7242 result = GST_AUTOPLUG_SELECT_SKIP;
7247 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7248 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7249 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7250 factory_name, player->ini.unsupported_codec_keyword[idx]);
7251 result = GST_AUTOPLUG_SELECT_SKIP;
7256 /* exclude webm format */
7257 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7258 * because webm format is not supportable.
7259 * If webm is disabled in "autoplug-continue", there is no state change
7260 * failure or error because the decodebin will expose the pad directly.
7261 * It make MSL invoke _prepare_async_callback.
7262 * So, we need to disable webm format in "autoplug-select" */
7263 if (caps_str && strstr(caps_str, "webm")) {
7264 LOGW("webm is not supported");
7265 result = GST_AUTOPLUG_SELECT_SKIP;
7269 /* check factory class for filtering */
7270 /* NOTE : msl don't need to use image plugins.
7271 * So, those plugins should be skipped for error handling.
7273 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7274 LOGD("skipping [%s] by not required", factory_name);
7275 result = GST_AUTOPLUG_SELECT_SKIP;
7279 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7280 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7281 // TO CHECK : subtitle if needed, add subparse exception.
7282 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7283 result = GST_AUTOPLUG_SELECT_SKIP;
7287 if (g_strrstr(factory_name, "mpegpsdemux")) {
7288 LOGD("skipping PS container - not support");
7289 result = GST_AUTOPLUG_SELECT_SKIP;
7293 if (g_strrstr(factory_name, "mssdemux"))
7294 player->smooth_streaming = TRUE;
7296 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7297 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7300 GstStructure *str = NULL;
7301 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7303 /* don't make video because of not required */
7304 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7305 (!player->set_mode.video_export)) {
7306 LOGD("no need video decoding, expose pad");
7307 result = GST_AUTOPLUG_SELECT_EXPOSE;
7311 /* get w/h for omx state-tune */
7312 /* FIXME: deprecated? */
7313 str = gst_caps_get_structure(caps, 0);
7314 gst_structure_get_int(str, "width", &width);
7317 if (player->v_stream_caps) {
7318 gst_caps_unref(player->v_stream_caps);
7319 player->v_stream_caps = NULL;
7322 player->v_stream_caps = gst_caps_copy(caps);
7323 LOGD("take caps for video state tune");
7324 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7328 if (g_strrstr(klass, "Codec/Decoder")) {
7329 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7330 if (result != GST_AUTOPLUG_SELECT_TRY) {
7331 LOGW("skip add decoder");
7337 MMPLAYER_FREEIF(caps_str);
7343 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7346 //mmplayer_t *player = (mmplayer_t *)data;
7347 GstCaps *caps = NULL;
7349 LOGD("[Decodebin2] pad-removed signal");
7351 caps = gst_pad_query_caps(new_pad, NULL);
7353 LOGW("query caps is NULL");
7357 gchar *caps_str = NULL;
7358 caps_str = gst_caps_to_string(caps);
7360 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7362 MMPLAYER_FREEIF(caps_str);
7363 gst_caps_unref(caps);
7367 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7369 mmplayer_t *player = (mmplayer_t *)data;
7370 GstIterator *iter = NULL;
7371 GValue item = { 0, };
7373 gboolean done = FALSE;
7374 gboolean is_all_drained = TRUE;
7377 MMPLAYER_RETURN_IF_FAIL(player);
7379 LOGD("got drained signal");
7381 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7382 LOGW("Fail to get cmd lock");
7386 if (!__mmplayer_verify_gapless_play_path(player)) {
7387 LOGD("decoding is finished.");
7388 MMPLAYER_CMD_UNLOCK(player);
7392 _mmplayer_set_reconfigure_state(player, TRUE);
7393 MMPLAYER_CMD_UNLOCK(player);
7395 /* check decodebin src pads whether they received EOS or not */
7396 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7399 switch (gst_iterator_next(iter, &item)) {
7400 case GST_ITERATOR_OK:
7401 pad = g_value_get_object(&item);
7402 if (pad && !GST_PAD_IS_EOS(pad)) {
7403 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7404 is_all_drained = FALSE;
7407 g_value_reset(&item);
7409 case GST_ITERATOR_RESYNC:
7410 gst_iterator_resync(iter);
7412 case GST_ITERATOR_ERROR:
7413 case GST_ITERATOR_DONE:
7418 g_value_unset(&item);
7419 gst_iterator_free(iter);
7421 if (!is_all_drained) {
7422 LOGD("Wait util the all pads get EOS.");
7427 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7428 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7430 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7431 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7432 __mmplayer_deactivate_old_path(player);
7438 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7440 mmplayer_t *player = (mmplayer_t *)data;
7441 const gchar *klass = NULL;
7442 gchar *factory_name = NULL;
7444 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7445 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7447 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7449 if (__mmplayer_add_dump_buffer_probe(player, element))
7450 LOGD("add buffer probe");
7452 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7453 gchar *selected = NULL;
7454 selected = g_strdup(GST_ELEMENT_NAME(element));
7455 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7458 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7459 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7460 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7462 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7463 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7465 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7466 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7467 "max-video-width", player->adaptive_info.limit.width,
7468 "max-video-height", player->adaptive_info.limit.height, NULL);
7470 } else if (g_strrstr(klass, "Demuxer")) {
7472 LOGD("plugged element is demuxer. take it");
7474 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7475 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7478 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7479 int surface_type = 0;
7481 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7484 // to support trust-zone only
7485 if (g_strrstr(factory_name, "asfdemux")) {
7486 LOGD("set file-location %s", player->profile.uri);
7487 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7488 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7489 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7490 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7491 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7492 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7493 (__mmplayer_is_only_mp3_type(player->type))) {
7494 LOGD("[mpegaudioparse] set streaming pull mode.");
7495 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7497 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7498 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7501 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7502 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7503 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7505 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7506 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7508 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7509 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7510 (MMPLAYER_IS_DASH_STREAMING(player))) {
7511 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7512 _mm_player_streaming_set_multiqueue(player->streamer, element);
7513 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7522 __mmplayer_release_misc(mmplayer_t *player)
7525 bool cur_mode = player->set_mode.rich_audio;
7528 MMPLAYER_RETURN_IF_FAIL(player);
7530 player->sent_bos = FALSE;
7531 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7533 player->seek_state = MMPLAYER_SEEK_NONE;
7535 player->total_bitrate = 0;
7536 player->total_maximum_bitrate = 0;
7538 player->not_found_demuxer = 0;
7540 player->last_position = 0;
7541 player->duration = 0;
7542 player->http_content_size = 0;
7543 player->not_supported_codec = MISSING_PLUGIN_NONE;
7544 player->can_support_codec = FOUND_PLUGIN_NONE;
7545 player->pending_seek.is_pending = false;
7546 player->pending_seek.pos = 0;
7547 player->msg_posted = FALSE;
7548 player->has_many_types = FALSE;
7549 player->is_subtitle_force_drop = FALSE;
7550 player->play_subtitle = FALSE;
7551 player->adjust_subtitle_pos = 0;
7552 player->has_closed_caption = FALSE;
7553 player->set_mode.video_export = false;
7554 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7555 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7557 player->set_mode.rich_audio = cur_mode;
7559 if (player->audio_device_cb_id > 0 &&
7560 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7561 LOGW("failed to remove audio device_connected_callback");
7562 player->audio_device_cb_id = 0;
7564 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7565 player->bitrate[i] = 0;
7566 player->maximum_bitrate[i] = 0;
7569 /* free memory related to audio effect */
7570 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7572 if (player->adaptive_info.var_list) {
7573 g_list_free_full(player->adaptive_info.var_list, g_free);
7574 player->adaptive_info.var_list = NULL;
7577 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7578 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7579 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7581 /* Reset video360 settings to their defaults in case if the pipeline is to be
7584 player->video360_metadata.is_spherical = -1;
7585 player->is_openal_plugin_used = FALSE;
7587 player->is_content_spherical = FALSE;
7588 player->is_video360_enabled = TRUE;
7589 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7590 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7591 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7592 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7593 player->video360_zoom = 1.0f;
7594 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7595 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7597 player->sound.rg_enable = false;
7599 __mmplayer_initialize_video_roi(player);
7604 __mmplayer_release_misc_post(mmplayer_t *player)
7606 char *original_uri = NULL;
7609 /* player->pipeline is already released before. */
7610 MMPLAYER_RETURN_IF_FAIL(player);
7612 player->video_decoded_cb = NULL;
7613 player->video_decoded_cb_user_param = NULL;
7614 player->video_stream_prerolled = false;
7616 player->audio_decoded_cb = NULL;
7617 player->audio_decoded_cb_user_param = NULL;
7618 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7620 player->audio_stream_changed_cb = NULL;
7621 player->audio_stream_changed_cb_user_param = NULL;
7623 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7625 /* clean found audio decoders */
7626 if (player->audio_decoders) {
7627 GList *a_dec = player->audio_decoders;
7628 for (; a_dec; a_dec = g_list_next(a_dec)) {
7629 gchar *name = a_dec->data;
7630 MMPLAYER_FREEIF(name);
7632 g_list_free(player->audio_decoders);
7633 player->audio_decoders = NULL;
7636 /* clean the uri list except original uri */
7637 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7638 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7640 LOGW("failed to get original uri info");
7642 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7643 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7645 GList *uri_list = player->uri_info.uri_list;
7646 for (; uri_list; uri_list = g_list_next(uri_list)) {
7647 gchar *uri = uri_list->data;
7648 if (original_uri != uri)
7649 MMPLAYER_FREEIF(uri);
7653 /* clear the audio stream buffer list */
7654 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7656 /* clear the video stream bo list */
7657 __mmplayer_video_stream_destroy_bo_list(player);
7658 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7660 if (player->profile.input_mem.buf) {
7661 free(player->profile.input_mem.buf);
7662 player->profile.input_mem.buf = NULL;
7664 player->profile.input_mem.len = 0;
7665 player->profile.input_mem.offset = 0;
7667 player->uri_info.uri_idx = 0;
7672 __mmplayer_check_subtitle(mmplayer_t *player)
7674 MMHandleType attrs = 0;
7675 char *subtitle_uri = NULL;
7679 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7681 /* get subtitle attribute */
7682 attrs = MMPLAYER_GET_ATTRS(player);
7686 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7687 if (!subtitle_uri || !strlen(subtitle_uri))
7690 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7691 player->is_external_subtitle_present = TRUE;
7699 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7701 MMPLAYER_RETURN_IF_FAIL(player);
7703 if (player->eos_timer) {
7704 LOGD("cancel eos timer");
7705 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7706 player->eos_timer = 0;
7713 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7717 MMPLAYER_RETURN_IF_FAIL(player);
7718 MMPLAYER_RETURN_IF_FAIL(sink);
7720 player->sink_elements = g_list_append(player->sink_elements, sink);
7726 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7730 MMPLAYER_RETURN_IF_FAIL(player);
7731 MMPLAYER_RETURN_IF_FAIL(sink);
7733 player->sink_elements = g_list_remove(player->sink_elements, sink);
7739 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7740 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7742 mmplayer_signal_item_t *item = NULL;
7745 MMPLAYER_RETURN_IF_FAIL(player);
7747 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7748 LOGE("invalid signal type [%d]", type);
7752 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7754 LOGE("cannot connect signal [%s]", signal);
7759 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7760 player->signals[type] = g_list_append(player->signals[type], item);
7766 /* NOTE : be careful with calling this api. please refer to below glib comment
7767 * glib comment : Note that there is a bug in GObject that makes this function much
7768 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7769 * will no longer be called, but, the signal handler is not currently disconnected.
7770 * If the instance is itself being freed at the same time than this doesn't matter,
7771 * since the signal will automatically be removed, but if instance persists,
7772 * then the signal handler will leak. You should not remove the signal yourself
7773 * because in a future versions of GObject, the handler will automatically be
7776 * It's possible to work around this problem in a way that will continue to work
7777 * with future versions of GObject by checking that the signal handler is still
7778 * connected before disconnected it:
7780 * if (g_signal_handler_is_connected(instance, id))
7781 * g_signal_handler_disconnect(instance, id);
7784 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7786 GList *sig_list = NULL;
7787 mmplayer_signal_item_t *item = NULL;
7791 MMPLAYER_RETURN_IF_FAIL(player);
7793 LOGD("release signals type : %d", type);
7795 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7796 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7797 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7798 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7799 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7800 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7804 sig_list = player->signals[type];
7806 for (; sig_list; sig_list = sig_list->next) {
7807 item = sig_list->data;
7809 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7810 if (g_signal_handler_is_connected(item->obj, item->sig))
7811 g_signal_handler_disconnect(item->obj, item->sig);
7814 MMPLAYER_FREEIF(item);
7817 g_list_free(player->signals[type]);
7818 player->signals[type] = NULL;
7826 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7828 mmplayer_t *player = 0;
7829 int prev_display_surface_type = 0;
7833 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7835 player = MM_PLAYER_CAST(handle);
7837 /* check video sinkbin is created */
7838 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7839 LOGW("Videosink is already created");
7840 return MM_ERROR_NONE;
7843 LOGD("videosink element is not yet ready");
7845 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7846 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7848 return MM_ERROR_INVALID_ARGUMENT;
7851 /* load previous attributes */
7852 if (player->attrs) {
7853 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7854 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7855 if (prev_display_surface_type == surface_type) {
7856 LOGD("incoming display surface type is same as previous one, do nothing..");
7858 return MM_ERROR_NONE;
7861 LOGE("failed to load attributes");
7863 return MM_ERROR_PLAYER_INTERNAL;
7866 /* videobin is not created yet, so we just set attributes related to display surface */
7867 LOGD("store display attribute for given surface type(%d)", surface_type);
7868 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7869 "display_overlay", wl_surface_id, NULL);
7872 return MM_ERROR_NONE;
7875 /* Note : if silent is true, then subtitle would not be displayed. :*/
7877 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7879 mmplayer_t *player = (mmplayer_t *)hplayer;
7883 /* check player handle */
7884 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7886 player->set_mode.subtitle_off = silent;
7888 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7892 return MM_ERROR_NONE;
7896 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7898 mmplayer_gst_element_t *mainbin = NULL;
7899 mmplayer_gst_element_t *textbin = NULL;
7900 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7901 GstState current_state = GST_STATE_VOID_PENDING;
7902 GstState element_state = GST_STATE_VOID_PENDING;
7903 GstState element_pending_state = GST_STATE_VOID_PENDING;
7905 GstEvent *event = NULL;
7906 int result = MM_ERROR_NONE;
7908 GstClock *curr_clock = NULL;
7909 GstClockTime base_time, start_time, curr_time;
7914 /* check player handle */
7915 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7917 player->pipeline->mainbin &&
7918 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7920 mainbin = player->pipeline->mainbin;
7921 textbin = player->pipeline->textbin;
7923 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7925 // sync clock with current pipeline
7926 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7927 curr_time = gst_clock_get_time(curr_clock);
7929 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7930 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7932 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7933 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7935 if (current_state > GST_STATE_READY) {
7936 // sync state with current pipeline
7937 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7938 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7939 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7941 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7942 if (GST_STATE_CHANGE_FAILURE == ret) {
7943 LOGE("fail to state change.");
7944 result = MM_ERROR_PLAYER_INTERNAL;
7948 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7949 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7952 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7953 gst_object_unref(curr_clock);
7956 // seek to current position
7957 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7958 result = MM_ERROR_PLAYER_INVALID_STATE;
7959 LOGE("gst_element_query_position failed, invalid state");
7963 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7964 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);
7966 _mmplayer_gst_send_event_to_sink(player, event);
7968 result = MM_ERROR_PLAYER_INTERNAL;
7969 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7973 /* sync state with current pipeline */
7974 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7975 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7976 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7978 return MM_ERROR_NONE;
7981 /* release text pipeline resource */
7982 player->textsink_linked = 0;
7984 /* release signal */
7985 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7987 /* release textbin with it's childs */
7988 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7989 MMPLAYER_FREEIF(player->pipeline->textbin);
7990 player->pipeline->textbin = NULL;
7992 /* release subtitle elem */
7993 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7994 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8000 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8002 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8003 GstState current_state = GST_STATE_VOID_PENDING;
8005 MMHandleType attrs = 0;
8006 mmplayer_gst_element_t *mainbin = NULL;
8007 mmplayer_gst_element_t *textbin = NULL;
8009 gchar *subtitle_uri = NULL;
8010 int result = MM_ERROR_NONE;
8011 const gchar *charset = NULL;
8015 /* check player handle */
8016 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8018 player->pipeline->mainbin &&
8019 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8020 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8022 mainbin = player->pipeline->mainbin;
8023 textbin = player->pipeline->textbin;
8025 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8026 if (current_state < GST_STATE_READY) {
8027 result = MM_ERROR_PLAYER_INVALID_STATE;
8028 LOGE("Pipeline is not in proper state");
8032 attrs = MMPLAYER_GET_ATTRS(player);
8034 LOGE("cannot get content attribute");
8035 result = MM_ERROR_PLAYER_INTERNAL;
8039 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8040 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8041 LOGE("subtitle uri is not proper filepath");
8042 result = MM_ERROR_PLAYER_INVALID_URI;
8046 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8047 LOGE("failed to get storage info of subtitle path");
8048 result = MM_ERROR_PLAYER_INVALID_URI;
8052 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8053 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8055 if (!strcmp(filepath, subtitle_uri)) {
8056 LOGD("subtitle path is not changed");
8059 if (mm_player_set_attribute((MMHandleType)player, NULL,
8060 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8061 LOGE("failed to set attribute");
8066 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8067 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8068 player->subtitle_language_list = NULL;
8069 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8071 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8072 if (ret != GST_STATE_CHANGE_SUCCESS) {
8073 LOGE("failed to change state of textbin to READY");
8074 result = MM_ERROR_PLAYER_INTERNAL;
8078 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8079 if (ret != GST_STATE_CHANGE_SUCCESS) {
8080 LOGE("failed to change state of subparse to READY");
8081 result = MM_ERROR_PLAYER_INTERNAL;
8085 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8086 if (ret != GST_STATE_CHANGE_SUCCESS) {
8087 LOGE("failed to change state of filesrc to READY");
8088 result = MM_ERROR_PLAYER_INTERNAL;
8092 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8094 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8096 charset = _mmplayer_get_charset(filepath);
8098 LOGD("detected charset is %s", charset);
8099 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8102 result = _mmplayer_sync_subtitle_pipeline(player);
8109 /* API to switch between external subtitles */
8111 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8113 int result = MM_ERROR_NONE;
8114 mmplayer_t *player = (mmplayer_t *)hplayer;
8119 /* check player handle */
8120 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8122 /* filepath can be null in idle state */
8124 /* check file path */
8125 if ((path = strstr(filepath, "file://")))
8126 result = _mmplayer_exist_file_path(path + 7);
8128 result = _mmplayer_exist_file_path(filepath);
8130 if (result != MM_ERROR_NONE) {
8131 LOGE("invalid subtitle path 0x%X", result);
8132 return result; /* file not found or permission denied */
8136 if (!player->pipeline) {
8138 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8139 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8140 LOGE("failed to set attribute");
8141 return MM_ERROR_PLAYER_INTERNAL;
8144 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8145 /* check filepath */
8146 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8148 if (!__mmplayer_check_subtitle(player)) {
8149 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8150 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8151 LOGE("failed to set attribute");
8152 return MM_ERROR_PLAYER_INTERNAL;
8155 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8156 LOGE("fail to create text pipeline");
8157 return MM_ERROR_PLAYER_INTERNAL;
8160 result = _mmplayer_sync_subtitle_pipeline(player);
8162 result = __mmplayer_change_external_subtitle_language(player, filepath);
8165 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8166 player->is_external_subtitle_added_now = TRUE;
8168 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8169 if (!player->subtitle_language_list) {
8170 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8171 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8172 LOGW("subtitle language list is not updated yet");
8174 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8182 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8184 guint active_idx = 0;
8185 GstStream *stream = NULL;
8186 GList *streams = NULL;
8187 GstEvent *ev = NULL;
8189 LOGD("Switching Streams... type: %d, index: %d", type, index);
8191 player->track[type].active_track_index = index;
8193 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8194 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8195 if (player->track[i].total_track_num > 0) {
8196 active_idx = player->track[i].active_track_index;
8197 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8198 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8199 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8203 ev = gst_event_new_select_streams(streams);
8204 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, ev);
8205 g_list_free(streams);
8207 return MM_ERROR_NONE;
8211 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8213 int result = MM_ERROR_NONE;
8214 gchar *change_pad_name = NULL;
8215 GstPad *sinkpad = NULL;
8216 mmplayer_gst_element_t *mainbin = NULL;
8217 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8218 GstCaps *caps = NULL;
8219 gint total_track_num = 0;
8223 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8224 MM_ERROR_PLAYER_NOT_INITIALIZED);
8226 LOGD("Change Track(%d) to %d", type, index);
8228 mainbin = player->pipeline->mainbin;
8230 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8231 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8232 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8233 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8235 /* Changing Video Track is not supported. */
8236 LOGE("Track Type Error");
8240 if (mainbin[elem_idx].gst == NULL) {
8241 result = MM_ERROR_PLAYER_NO_OP;
8242 LOGD("Req track doesn't exist");
8246 total_track_num = player->track[type].total_track_num;
8247 if (total_track_num <= 0) {
8248 result = MM_ERROR_PLAYER_NO_OP;
8249 LOGD("Language list is not available");
8253 if ((index < 0) || (index >= total_track_num)) {
8254 result = MM_ERROR_INVALID_ARGUMENT;
8255 LOGD("Not a proper index : %d", index);
8259 /*To get the new pad from the selector*/
8260 change_pad_name = g_strdup_printf("sink_%u", index);
8261 if (change_pad_name == NULL) {
8262 result = MM_ERROR_PLAYER_INTERNAL;
8263 LOGD("Pad does not exists");
8267 LOGD("new active pad name: %s", change_pad_name);
8269 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8270 if (sinkpad == NULL) {
8271 LOGD("sinkpad is NULL");
8272 result = MM_ERROR_PLAYER_INTERNAL;
8276 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8277 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8279 caps = gst_pad_get_current_caps(sinkpad);
8280 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8283 gst_object_unref(sinkpad);
8285 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8286 __mmplayer_set_audio_attrs(player, caps);
8289 MMPLAYER_FREEIF(change_pad_name);
8294 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8296 int result = MM_ERROR_NONE;
8297 mmplayer_t *player = NULL;
8298 mmplayer_gst_element_t *mainbin = NULL;
8300 gint current_active_index = 0;
8302 GstState current_state = GST_STATE_VOID_PENDING;
8307 player = (mmplayer_t *)hplayer;
8308 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8310 if (!player->pipeline) {
8311 LOGE("Track %d pre setting -> %d", type, index);
8313 player->track[type].active_track_index = index;
8317 mainbin = player->pipeline->mainbin;
8319 current_active_index = player->track[type].active_track_index;
8321 /*If index is same as running index no need to change the pad*/
8322 if (current_active_index == index)
8325 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8326 result = MM_ERROR_PLAYER_INVALID_STATE;
8330 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8331 if (current_state < GST_STATE_PAUSED) {
8332 result = MM_ERROR_PLAYER_INVALID_STATE;
8333 LOGW("Pipeline not in porper state");
8337 if (MMPLAYER_USE_URIDECODEBIN3(player)) {
8338 result = __mmplayer_switch_stream(player, type, index);
8340 result = __mmplayer_change_selector_pad(player, type, index);
8342 if (result != MM_ERROR_NONE) {
8343 LOGE("failed to change track");
8347 player->track[type].active_track_index = index;
8349 if (!MMPLAYER_USE_URIDECODEBIN3(player)) {
8350 GstEvent *event = NULL;
8351 if (current_state == GST_STATE_PLAYING) {
8352 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8353 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8354 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8356 _mmplayer_gst_send_event_to_sink(player, event);
8358 result = MM_ERROR_PLAYER_INTERNAL;
8369 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8371 mmplayer_t *player = (mmplayer_t *)hplayer;
8375 /* check player handle */
8376 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8378 *silent = player->set_mode.subtitle_off;
8380 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8384 return MM_ERROR_NONE;
8388 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8390 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8391 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8393 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8394 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8398 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8399 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8400 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8401 mmplayer_dump_t *dump_s;
8402 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8403 if (dump_s == NULL) {
8404 LOGE("malloc fail");
8408 dump_s->dump_element_file = NULL;
8409 dump_s->dump_pad = NULL;
8410 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8412 if (dump_s->dump_pad) {
8413 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8414 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]);
8415 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8416 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);
8417 /* add list for removed buffer probe and close FILE */
8418 player->dump_list = g_list_append(player->dump_list, dump_s);
8419 LOGD("%s sink pad added buffer probe for dump", factory_name);
8422 MMPLAYER_FREEIF(dump_s);
8423 LOGE("failed to get %s sink pad added", factory_name);
8430 static GstPadProbeReturn
8431 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8433 FILE *dump_data = (FILE *)u_data;
8435 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8436 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8438 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8440 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8442 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8444 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8446 gst_buffer_unmap(buffer, &probe_info);
8448 return GST_PAD_PROBE_OK;
8452 __mmplayer_release_dump_list(GList *dump_list)
8454 GList *d_list = dump_list;
8459 for (; d_list; d_list = g_list_next(d_list)) {
8460 mmplayer_dump_t *dump_s = d_list->data;
8461 if (dump_s->dump_pad) {
8462 if (dump_s->probe_handle_id)
8463 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8464 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8466 if (dump_s->dump_element_file) {
8467 fclose(dump_s->dump_element_file);
8468 dump_s->dump_element_file = NULL;
8470 MMPLAYER_FREEIF(dump_s);
8472 g_list_free(dump_list);
8477 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8479 mmplayer_t *player = (mmplayer_t *)hplayer;
8483 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8484 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8486 *exist = (bool)player->has_closed_caption;
8490 return MM_ERROR_NONE;
8494 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8499 LOGD("unref internal gst buffer %p", buffer);
8501 gst_buffer_unref((GstBuffer *)buffer);
8508 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8510 mmplayer_t *player = (mmplayer_t *)hplayer;
8514 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8515 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8517 if (MMPLAYER_IS_STREAMING(player))
8518 *timeout = (int)player->ini.live_state_change_timeout;
8520 *timeout = (int)player->ini.localplayback_state_change_timeout;
8522 LOGD("timeout = %d", *timeout);
8525 return MM_ERROR_NONE;
8529 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8533 MMPLAYER_RETURN_IF_FAIL(player);
8535 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8537 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8538 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8539 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8540 player->storage_info[i].id = -1;
8541 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8543 if (path_type != MMPLAYER_PATH_MAX)
8552 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8554 int ret = MM_ERROR_NONE;
8555 mmplayer_t *player = (mmplayer_t *)hplayer;
8556 MMMessageParamType msg_param = {0, };
8559 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8561 LOGW("state changed storage %d:%d", id, state);
8563 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8564 return MM_ERROR_NONE;
8566 /* FIXME: text path should be handled seperately. */
8567 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8568 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8569 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8570 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8571 LOGW("external storage is removed");
8573 if (player->msg_posted == FALSE) {
8574 memset(&msg_param, 0, sizeof(MMMessageParamType));
8575 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8576 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8577 player->msg_posted = TRUE;
8580 /* unrealize the player */
8581 ret = _mmplayer_unrealize(hplayer);
8582 if (ret != MM_ERROR_NONE)
8583 LOGE("failed to unrealize");
8591 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8593 int ret = MM_ERROR_NONE;
8594 mmplayer_t *player = (mmplayer_t *)hplayer;
8595 int idx = 0, total = 0;
8596 gchar *result = NULL, *tmp = NULL;
8599 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8600 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8602 total = *num = g_list_length(player->adaptive_info.var_list);
8604 LOGW("There is no stream variant info.");
8608 result = g_strdup("");
8609 for (idx = 0 ; idx < total ; idx++) {
8610 stream_variant_t *v_data = NULL;
8611 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8614 gchar data[64] = {0};
8615 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8617 tmp = g_strconcat(result, data, NULL);
8621 LOGW("There is no variant data in %d", idx);
8626 *var_info = (char *)result;
8628 LOGD("variant info %d:%s", *num, *var_info);
8634 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8636 int ret = MM_ERROR_NONE;
8637 mmplayer_t *player = (mmplayer_t *)hplayer;
8640 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8642 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8644 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8645 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8646 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8648 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8649 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8650 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8651 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8653 /* FIXME: seek to current position for applying new variant limitation */
8662 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8664 int ret = MM_ERROR_NONE;
8665 mmplayer_t *player = (mmplayer_t *)hplayer;
8668 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8669 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8671 *bandwidth = player->adaptive_info.limit.bandwidth;
8672 *width = player->adaptive_info.limit.width;
8673 *height = player->adaptive_info.limit.height;
8675 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8682 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8684 int ret = MM_ERROR_NONE;
8685 mmplayer_t *player = (mmplayer_t *)hplayer;
8688 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8689 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8690 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8692 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8694 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8695 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8696 else /* live case */
8697 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8699 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8706 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8708 #define IDX_FIRST_SW_CODEC 0
8709 mmplayer_t *player = (mmplayer_t *)hplayer;
8710 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8713 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8715 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8716 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8717 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8719 switch (stream_type) {
8720 case MM_PLAYER_STREAM_TYPE_AUDIO:
8721 /* to support audio codec selection, codec info have to be added in ini file as below.
8722 audio codec element hw = xxxx
8723 audio codec element sw = avdec
8724 and in case of audio hw codec is supported and selected,
8725 audio filter elements should be applied depending on the hw capabilities.
8727 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8728 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8729 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8730 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8731 LOGE("There is no audio codec info for codec_type %d", codec_type);
8732 return MM_ERROR_PLAYER_NO_OP;
8735 case MM_PLAYER_STREAM_TYPE_VIDEO:
8736 /* to support video codec selection, codec info have to be added in ini file as below.
8737 video codec element hw = omx
8738 video codec element sw = avdec */
8739 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8740 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8741 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8742 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8743 LOGE("There is no video codec info for codec_type %d", codec_type);
8744 return MM_ERROR_PLAYER_NO_OP;
8748 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8749 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8753 LOGD("update %s codec_type to %d", attr_name, codec_type);
8754 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8757 return MM_ERROR_NONE;
8761 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8763 mmplayer_t *player = (mmplayer_t *)hplayer;
8764 GstElement *rg_vol_element = NULL;
8768 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8770 player->sound.rg_enable = enabled;
8772 /* just hold rgvolume enable value if pipeline is not ready */
8773 if (!player->pipeline || !player->pipeline->audiobin) {
8774 LOGD("pipeline is not ready. holding rgvolume enable value");
8775 return MM_ERROR_NONE;
8778 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8780 if (!rg_vol_element) {
8781 LOGD("rgvolume element is not created");
8782 return MM_ERROR_PLAYER_INTERNAL;
8786 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8788 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8792 return MM_ERROR_NONE;
8796 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8798 mmplayer_t *player = (mmplayer_t *)hplayer;
8799 GstElement *rg_vol_element = NULL;
8800 gboolean enable = FALSE;
8804 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8805 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8807 /* just hold enable_rg value if pipeline is not ready */
8808 if (!player->pipeline || !player->pipeline->audiobin) {
8809 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8810 *enabled = player->sound.rg_enable;
8811 return MM_ERROR_NONE;
8814 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8816 if (!rg_vol_element) {
8817 LOGD("rgvolume element is not created");
8818 return MM_ERROR_PLAYER_INTERNAL;
8821 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8822 *enabled = (bool)enable;
8826 return MM_ERROR_NONE;
8830 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8832 mmplayer_t *player = (mmplayer_t *)hplayer;
8833 MMHandleType attrs = 0;
8835 int ret = MM_ERROR_NONE;
8839 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8841 attrs = MMPLAYER_GET_ATTRS(player);
8842 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8844 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
8846 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8847 return MM_ERROR_PLAYER_INTERNAL;
8850 player->video_roi.scale_x = scale_x;
8851 player->video_roi.scale_y = scale_y;
8852 player->video_roi.scale_width = scale_width;
8853 player->video_roi.scale_height = scale_height;
8855 /* check video sinkbin is created */
8856 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8857 return MM_ERROR_NONE;
8859 if (!gst_video_overlay_set_video_roi_area(
8860 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8861 scale_x, scale_y, scale_width, scale_height))
8862 ret = MM_ERROR_PLAYER_INTERNAL;
8864 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8865 scale_x, scale_y, scale_width, scale_height);
8873 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8875 mmplayer_t *player = (mmplayer_t *)hplayer;
8876 int ret = MM_ERROR_NONE;
8880 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8881 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8883 *scale_x = player->video_roi.scale_x;
8884 *scale_y = player->video_roi.scale_y;
8885 *scale_width = player->video_roi.scale_width;
8886 *scale_height = player->video_roi.scale_height;
8888 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8889 *scale_x, *scale_y, *scale_width, *scale_height);
8895 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8897 mmplayer_t *player = (mmplayer_t *)hplayer;
8901 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8903 player->client_pid = pid;
8905 LOGD("client pid[%d] %p", pid, player);
8909 return MM_ERROR_NONE;
8913 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
8915 mmplayer_t *player = (mmplayer_t *)hplayer;
8916 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8917 enum audio_element_id elem_id = MMPLAYER_A_NUM;
8921 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8922 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
8925 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
8927 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
8929 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
8930 return MM_ERROR_NONE;
8932 /* in case of audio codec default type is HW */
8934 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
8935 if (player->ini.support_audio_effect)
8936 return MM_ERROR_NONE;
8937 elem_id = MMPLAYER_A_FILTER;
8939 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
8940 if (player->ini.support_replaygain_control)
8941 return MM_ERROR_NONE;
8942 elem_id = MMPLAYER_A_RGVOL;
8944 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
8945 if (player->ini.support_pitch_control)
8946 return MM_ERROR_NONE;
8947 elem_id = MMPLAYER_A_PITCH;
8949 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
8950 if (player->ini.support_audio_effect)
8951 return MM_ERROR_NONE;
8953 /* default case handling is not required */
8956 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
8957 LOGW("audio control option [%d] is not available", opt);
8960 /* setting pcm exporting option is allowed before READY state */
8961 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
8962 return MM_ERROR_PLAYER_INVALID_STATE;
8964 /* check whether the audio filter exist or not after READY state,
8965 because the sw codec could be added during auto-plugging in some cases */
8966 if (!player->pipeline ||
8967 !player->pipeline->audiobin ||
8968 !player->pipeline->audiobin[elem_id].gst) {
8969 LOGW("there is no audio elem [%d]", elem_id);
8974 LOGD("audio control opt %d, available %d", opt, *available);
8978 return MM_ERROR_NONE;
8982 __mmplayer_update_duration_value(mmplayer_t *player)
8984 gboolean ret = FALSE;
8985 gint64 dur_nsec = 0;
8986 LOGD("try to update duration");
8988 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8989 player->duration = dur_nsec;
8990 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8994 if (player->duration < 0) {
8995 LOGW("duration is Non-Initialized !!!");
8996 player->duration = 0;
8999 /* update streaming service type */
9000 player->streaming_type = _mmplayer_get_stream_service_type(player);
9002 /* check duration is OK */
9003 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9004 /* FIXIT : find another way to get duration here. */
9005 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9011 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9013 /* update audio params
9014 NOTE : We need original audio params and it can be only obtained from src pad of audio
9015 decoder. Below code only valid when we are not using 'resampler' just before
9016 'audioconverter'. */
9017 GstCaps *caps_a = NULL;
9019 gint samplerate = 0, channels = 0;
9020 GstStructure *p = NULL;
9021 GstElement *aconv = NULL;
9023 LOGD("try to update audio attrs");
9025 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9027 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9028 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9029 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9030 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9032 LOGE("there is no audio converter");
9036 pad = gst_element_get_static_pad(aconv, "sink");
9039 LOGW("failed to get pad from audio converter");
9043 caps_a = gst_pad_get_current_caps(pad);
9045 LOGW("not ready to get audio caps");
9046 gst_object_unref(pad);
9050 p = gst_caps_get_structure(caps_a, 0);
9052 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9054 gst_structure_get_int(p, "rate", &samplerate);
9055 gst_structure_get_int(p, "channels", &channels);
9057 mm_player_set_attribute((MMHandleType)player, NULL,
9058 "content_audio_samplerate", samplerate,
9059 "content_audio_channels", channels, NULL);
9061 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9063 gst_caps_unref(caps_a);
9064 gst_object_unref(pad);
9070 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9072 LOGD("try to update video attrs");
9074 GstCaps *caps_v = NULL;
9078 GstStructure *p = NULL;
9080 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9081 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9083 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9085 LOGD("no videosink sink pad");
9089 caps_v = gst_pad_get_current_caps(pad);
9090 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9091 if (!caps_v && player->v_stream_caps) {
9092 caps_v = player->v_stream_caps;
9093 gst_caps_ref(caps_v);
9097 LOGD("no negitiated caps from videosink");
9098 gst_object_unref(pad);
9102 p = gst_caps_get_structure(caps_v, 0);
9103 gst_structure_get_int(p, "width", &width);
9104 gst_structure_get_int(p, "height", &height);
9106 mm_player_set_attribute((MMHandleType)player, NULL,
9107 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9109 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9111 SECURE_LOGD("width : %d height : %d", width, height);
9113 gst_caps_unref(caps_v);
9114 gst_object_unref(pad);
9117 mm_player_set_attribute((MMHandleType)player, NULL,
9118 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9119 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9126 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9128 gboolean ret = FALSE;
9129 guint64 data_size = 0;
9133 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9134 if (!player->duration)
9137 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9138 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9139 if (stat(path, &sb) == 0)
9140 data_size = (guint64)sb.st_size;
9142 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9143 data_size = player->http_content_size;
9146 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9149 guint64 bitrate = 0;
9150 guint64 msec_dur = 0;
9152 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9154 bitrate = data_size * 8 * 1000 / msec_dur;
9155 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9156 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9157 mm_player_set_attribute((MMHandleType)player, NULL,
9158 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9161 LOGD("player duration is less than 0");
9165 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9166 if (player->total_bitrate) {
9167 mm_player_set_attribute((MMHandleType)player, NULL,
9168 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9177 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9179 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9180 data->uri_type = uri_type;
9184 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9186 int ret = MM_ERROR_PLAYER_INVALID_URI;
9188 char *buffer = NULL;
9189 char *seperator = strchr(path, ',');
9190 char ext[100] = {0,}, size[100] = {0,};
9193 if ((buffer = strstr(path, "ext="))) {
9194 buffer += strlen("ext=");
9196 if (strlen(buffer)) {
9197 strncpy(ext, buffer, 99);
9199 if ((seperator = strchr(ext, ','))
9200 || (seperator = strchr(ext, ' '))
9201 || (seperator = strchr(ext, '\0'))) {
9202 seperator[0] = '\0';
9207 if ((buffer = strstr(path, "size="))) {
9208 buffer += strlen("size=");
9210 if (strlen(buffer) > 0) {
9211 strncpy(size, buffer, 99);
9213 if ((seperator = strchr(size, ','))
9214 || (seperator = strchr(size, ' '))
9215 || (seperator = strchr(size, '\0'))) {
9216 seperator[0] = '\0';
9219 mem_size = atoi(size);
9224 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9226 if (mem_size && param) {
9227 if (data->input_mem.buf)
9228 free(data->input_mem.buf);
9229 data->input_mem.buf = malloc(mem_size);
9231 if (data->input_mem.buf) {
9232 memcpy(data->input_mem.buf, param, mem_size);
9233 data->input_mem.len = mem_size;
9234 ret = MM_ERROR_NONE;
9236 LOGE("failed to alloc mem %d", mem_size);
9237 ret = MM_ERROR_PLAYER_INTERNAL;
9240 data->input_mem.offset = 0;
9241 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9248 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9250 gchar *location = NULL;
9253 int ret = MM_ERROR_NONE;
9255 if ((path = strstr(uri, "file://"))) {
9256 location = g_filename_from_uri(uri, NULL, &err);
9257 if (!location || (err != NULL)) {
9258 LOGE("Invalid URI '%s' for filesrc: %s", path,
9259 (err != NULL) ? err->message : "unknown error");
9263 MMPLAYER_FREEIF(location);
9265 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9266 return MM_ERROR_PLAYER_INVALID_URI;
9268 LOGD("path from uri: %s", location);
9271 path = (location != NULL) ? (location) : ((char *)uri);
9274 ret = _mmplayer_exist_file_path(path);
9276 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9277 if (ret == MM_ERROR_NONE) {
9278 if (_mmplayer_is_sdp_file(path)) {
9279 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9280 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9281 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9283 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9284 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9286 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9287 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9289 LOGE("invalid uri, could not play..");
9290 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9293 MMPLAYER_FREEIF(location);
9298 static mmplayer_video_decoded_data_info_t *
9299 __mmplayer_create_stream_from_pad(GstPad *pad)
9301 GstCaps *caps = NULL;
9302 GstStructure *structure = NULL;
9303 unsigned int fourcc = 0;
9304 const gchar *string_format = NULL;
9305 mmplayer_video_decoded_data_info_t *stream = NULL;
9307 MMPixelFormatType format;
9310 caps = gst_pad_get_current_caps(pad);
9312 LOGE("Caps is NULL.");
9317 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9319 structure = gst_caps_get_structure(caps, 0);
9320 gst_structure_get_int(structure, "width", &width);
9321 gst_structure_get_int(structure, "height", &height);
9322 string_format = gst_structure_get_string(structure, "format");
9325 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9326 format = _mmplayer_get_pixtype(fourcc);
9327 gst_video_info_from_caps(&info, caps);
9328 gst_caps_unref(caps);
9331 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9332 LOGE("Wrong condition!!");
9336 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9338 LOGE("failed to alloc mem for video data");
9342 stream->width = width;
9343 stream->height = height;
9344 stream->format = format;
9345 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9351 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9353 unsigned int pitch = 0;
9354 unsigned int size = 0;
9356 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9359 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9360 bo = gst_tizen_memory_get_bos(mem, index);
9362 stream->bo[index] = tbm_bo_ref(bo);
9364 LOGE("failed to get bo for index %d", index);
9367 for (index = 0; index < stream->plane_num; index++) {
9368 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9369 stream->stride[index] = pitch;
9371 stream->elevation[index] = size / pitch;
9373 stream->elevation[index] = stream->height;
9378 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9380 if (stream->format == MM_PIXEL_FORMAT_I420) {
9381 int ret = TBM_SURFACE_ERROR_NONE;
9382 tbm_surface_h surface;
9383 tbm_surface_info_s info;
9385 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9387 ret = tbm_surface_get_info(surface, &info);
9388 if (ret != TBM_SURFACE_ERROR_NONE) {
9389 tbm_surface_destroy(surface);
9393 tbm_surface_destroy(surface);
9394 stream->stride[0] = info.planes[0].stride;
9395 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9396 stream->stride[1] = info.planes[1].stride;
9397 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9398 stream->stride[2] = info.planes[2].stride;
9399 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9400 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9401 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9402 stream->stride[0] = stream->width * 4;
9403 stream->elevation[0] = stream->height;
9404 stream->bo_size = stream->stride[0] * stream->height;
9406 LOGE("Not support format %d", stream->format);
9414 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9416 tbm_bo_handle thandle;
9418 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9419 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9420 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9424 unsigned char *src = NULL;
9425 unsigned char *dest = NULL;
9426 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9428 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9430 LOGE("fail to gst_memory_map");
9434 if (!mapinfo.data) {
9435 LOGE("data pointer is wrong");
9439 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9440 if (!stream->bo[0]) {
9441 LOGE("Fail to tbm_bo_alloc!!");
9445 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9447 LOGE("thandle pointer is wrong");
9451 if (stream->format == MM_PIXEL_FORMAT_I420) {
9452 src_stride[0] = GST_ROUND_UP_4(stream->width);
9453 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9454 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9455 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9458 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9459 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9461 for (i = 0; i < 3; i++) {
9462 src = mapinfo.data + src_offset[i];
9463 dest = thandle.ptr + dest_offset[i];
9468 for (j = 0; j < stream->height >> k; j++) {
9469 memcpy(dest, src, stream->width>>k);
9470 src += src_stride[i];
9471 dest += stream->stride[i];
9474 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9475 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9477 LOGE("Not support format %d", stream->format);
9481 tbm_bo_unmap(stream->bo[0]);
9482 gst_memory_unmap(mem, &mapinfo);
9488 tbm_bo_unmap(stream->bo[0]);
9491 gst_memory_unmap(mem, &mapinfo);
9497 __mmplayer_set_pause_state(mmplayer_t *player)
9499 if (player->sent_bos)
9502 /* rtsp case, get content attrs by GstMessage */
9503 if (MMPLAYER_IS_RTSP_STREAMING(player))
9506 /* it's first time to update all content attrs. */
9507 _mmplayer_update_content_attrs(player, ATTR_ALL);
9511 __mmplayer_set_playing_state(mmplayer_t *player)
9513 gchar *audio_codec = NULL;
9515 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9516 /* initialize because auto resume is done well. */
9517 player->resumed_by_rewind = FALSE;
9518 player->playback_rate = 1.0;
9521 if (player->sent_bos)
9524 /* try to get content metadata */
9526 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9527 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9528 * legacy mmfw-player api
9530 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9532 if ((player->cmd == MMPLAYER_COMMAND_START)
9533 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9534 __mmplayer_handle_missed_plugin(player);
9537 /* check audio codec field is set or not
9538 * we can get it from typefinder or codec's caps.
9540 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9542 /* The codec format can't be sent for audio only case like amr, mid etc.
9543 * Because, parser don't make related TAG.
9544 * So, if it's not set yet, fill it with found data.
9547 if (g_strrstr(player->type, "audio/midi"))
9548 audio_codec = "MIDI";
9549 else if (g_strrstr(player->type, "audio/x-amr"))
9550 audio_codec = "AMR";
9551 else if (g_strrstr(player->type, "audio/mpeg")
9552 && !g_strrstr(player->type, "mpegversion=(int)1"))
9553 audio_codec = "AAC";
9555 audio_codec = "unknown";
9557 if (mm_player_set_attribute((MMHandleType)player, NULL,
9558 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9559 LOGE("failed to set attribute");
9561 LOGD("set audio codec type with caps");