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_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51 #include "mm_player_gst.h"
53 #include <system_info.h>
54 #include <sound_manager.h>
55 #include <gst/allocators/gsttizenmemory.h>
56 #include <tbm_surface_internal.h>
58 /*===========================================================================================
60 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
62 ========================================================================================== */
64 /*---------------------------------------------------------------------------
65 | GLOBAL CONSTANT DEFINITIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | IMPORTED VARIABLE DECLARATIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
73 | IMPORTED FUNCTION DECLARATIONS: |
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
78 ---------------------------------------------------------------------------*/
79 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
80 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
82 #define MM_VOLUME_FACTOR_DEFAULT 1.0
83 #define MM_VOLUME_FACTOR_MIN 0
84 #define MM_VOLUME_FACTOR_MAX 1.0
86 /* Don't need to sleep for sound fadeout
87 * fadeout related fucntion will be deleted(Deprecated)
89 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
91 #define DEFAULT_PLAYBACK_RATE 1.0
93 #define PLAYER_DISPLAY_MODE_DST_ROI 5
95 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
97 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
98 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
99 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
100 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
102 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
103 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
105 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
107 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
108 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
109 #define DEFAULT_PCM_OUT_CHANNEL 2
111 /*---------------------------------------------------------------------------
112 | LOCAL CONSTANT DEFINITIONS: |
113 ---------------------------------------------------------------------------*/
115 /*---------------------------------------------------------------------------
116 | LOCAL DATA TYPE DEFINITIONS: |
117 ---------------------------------------------------------------------------*/
118 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
119 We are defining our own and will be removed when it actually exposed */
121 GST_AUTOPLUG_SELECT_TRY,
122 GST_AUTOPLUG_SELECT_EXPOSE,
123 GST_AUTOPLUG_SELECT_SKIP
124 } GstAutoplugSelectResult;
126 /*---------------------------------------------------------------------------
127 | GLOBAL VARIABLE DEFINITIONS: |
128 ---------------------------------------------------------------------------*/
130 /*---------------------------------------------------------------------------
131 | LOCAL VARIABLE DEFINITIONS: |
132 ---------------------------------------------------------------------------*/
133 static sound_stream_info_h stream_info;
135 /*---------------------------------------------------------------------------
136 | LOCAL FUNCTION PROTOTYPES: |
137 ---------------------------------------------------------------------------*/
138 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
141 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
142 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
143 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
145 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
146 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
147 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
148 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
150 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
151 static void __mmplayer_release_misc(mmplayer_t *player);
152 static void __mmplayer_release_misc_post(mmplayer_t *player);
153 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
154 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
155 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
156 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
157 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
159 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
160 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
161 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
162 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
163 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
164 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
165 static gpointer __mmplayer_gapless_play_thread(gpointer data);
166 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
167 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
168 static void __mmplayer_release_dump_list(GList *dump_list);
169 static int __mmplayer_gst_realize(mmplayer_t *player);
170 static int __mmplayer_gst_unrealize(mmplayer_t *player);
171 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
172 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
175 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
176 static void __mmplayer_check_pipeline(mmplayer_t *player);
177 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
178 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
179 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
180 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
181 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
182 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
183 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
184 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
185 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
186 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
187 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
189 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
190 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
191 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
193 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
194 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
195 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
196 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
198 static void __mmplayer_set_pause_state(mmplayer_t *player);
199 static void __mmplayer_set_playing_state(mmplayer_t *player);
200 /*===========================================================================================
202 | FUNCTION DEFINITIONS |
204 ========================================================================================== */
206 /* This function should be called after the pipeline goes PAUSED or higher
209 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
211 static gboolean has_duration = FALSE;
212 static gboolean has_video_attrs = FALSE;
213 static gboolean has_audio_attrs = FALSE;
214 static gboolean has_bitrate = FALSE;
215 gboolean missing_only = FALSE;
216 gboolean all = FALSE;
217 MMHandleType attrs = 0;
221 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
223 /* check player state here */
224 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
225 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
226 /* give warning now only */
227 LOGW("be careful. content attributes may not available in this state ");
230 /* get content attribute first */
231 attrs = MMPLAYER_GET_ATTRS(player);
233 LOGE("cannot get content attribute");
237 /* get update flag */
239 if (flag & ATTR_MISSING_ONLY) {
241 LOGD("updating missed attr only");
244 if (flag & ATTR_ALL) {
246 has_duration = FALSE;
247 has_video_attrs = FALSE;
248 has_audio_attrs = FALSE;
251 LOGD("updating all attrs");
254 if (missing_only && all) {
255 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
256 missing_only = FALSE;
259 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
260 has_duration = __mmplayer_update_duration_value(player);
262 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
263 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
265 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
266 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
268 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
269 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
277 _mmplayer_get_stream_service_type(mmplayer_t *player)
279 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
283 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
285 player->pipeline->mainbin &&
286 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
287 STREAMING_SERVICE_NONE);
289 /* streaming service type if streaming */
290 if (!MMPLAYER_IS_STREAMING(player))
291 return STREAMING_SERVICE_NONE;
293 streaming_type = (player->duration == 0) ?
294 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
296 switch (streaming_type) {
297 case STREAMING_SERVICE_LIVE:
298 LOGD("it's live streaming");
300 case STREAMING_SERVICE_VOD:
301 LOGD("it's vod streaming");
304 LOGE("should not get here");
310 return streaming_type;
313 /* this function sets the player state and also report
314 * it to applicaton by calling callback function
317 _mmplayer_set_state(mmplayer_t *player, int state)
319 MMMessageParamType msg = {0, };
321 MMPLAYER_RETURN_IF_FAIL(player);
323 if (MMPLAYER_CURRENT_STATE(player) == state) {
324 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
325 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
329 /* update player states */
330 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
331 MMPLAYER_CURRENT_STATE(player) = state;
333 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
334 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
337 MMPLAYER_PRINT_STATE(player);
339 switch (MMPLAYER_CURRENT_STATE(player)) {
340 case MM_PLAYER_STATE_NULL:
341 case MM_PLAYER_STATE_READY:
343 case MM_PLAYER_STATE_PAUSED:
344 __mmplayer_set_pause_state(player);
346 case MM_PLAYER_STATE_PLAYING:
347 __mmplayer_set_playing_state(player);
349 case MM_PLAYER_STATE_NONE:
351 LOGW("invalid target state, there is nothing to do.");
356 /* post message to application */
357 if (MMPLAYER_TARGET_STATE(player) == state) {
358 /* fill the message with state of player */
359 msg.union_type = MM_MSG_UNION_STATE;
360 msg.state.previous = MMPLAYER_PREV_STATE(player);
361 msg.state.current = MMPLAYER_CURRENT_STATE(player);
363 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
365 /* state changed by resource callback */
366 if (player->interrupted_by_resource)
367 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
368 else /* state changed by usecase */
369 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
372 LOGD("intermediate state, do nothing.");
373 MMPLAYER_PRINT_STATE(player);
377 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
378 && !player->sent_bos) {
379 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
380 player->sent_bos = TRUE;
387 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
389 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
390 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
392 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
394 LOGD("incomming command : %d ", command);
396 current_state = MMPLAYER_CURRENT_STATE(player);
397 pending_state = MMPLAYER_PENDING_STATE(player);
399 MMPLAYER_PRINT_STATE(player);
402 case MMPLAYER_COMMAND_CREATE:
404 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
406 if (current_state == MM_PLAYER_STATE_NULL ||
407 current_state == MM_PLAYER_STATE_READY ||
408 current_state == MM_PLAYER_STATE_PAUSED ||
409 current_state == MM_PLAYER_STATE_PLAYING)
414 case MMPLAYER_COMMAND_DESTROY:
416 /* destroy can called anytime */
418 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
422 case MMPLAYER_COMMAND_REALIZE:
424 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
426 if (pending_state != MM_PLAYER_STATE_NONE) {
429 /* need ready state to realize */
430 if (current_state == MM_PLAYER_STATE_READY)
433 if (current_state != MM_PLAYER_STATE_NULL)
439 case MMPLAYER_COMMAND_UNREALIZE:
441 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
443 if (current_state == MM_PLAYER_STATE_NULL)
448 case MMPLAYER_COMMAND_START:
450 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
452 if (pending_state == MM_PLAYER_STATE_NONE) {
453 if (current_state == MM_PLAYER_STATE_PLAYING)
455 else if (current_state != MM_PLAYER_STATE_READY &&
456 current_state != MM_PLAYER_STATE_PAUSED)
458 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
460 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
461 LOGD("player is going to paused state, just change the pending state as playing");
468 case MMPLAYER_COMMAND_STOP:
470 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
472 if (current_state == MM_PLAYER_STATE_READY)
475 /* need playing/paused state to stop */
476 if (current_state != MM_PLAYER_STATE_PLAYING &&
477 current_state != MM_PLAYER_STATE_PAUSED)
482 case MMPLAYER_COMMAND_PAUSE:
484 if (MMPLAYER_IS_LIVE_STREAMING(player))
487 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
488 goto NOT_COMPLETED_SEEK;
490 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
492 if (pending_state == MM_PLAYER_STATE_NONE) {
493 if (current_state == MM_PLAYER_STATE_PAUSED)
495 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
497 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
499 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
500 if (current_state == MM_PLAYER_STATE_PAUSED)
501 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
508 case MMPLAYER_COMMAND_RESUME:
510 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
511 goto NOT_COMPLETED_SEEK;
513 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
515 if (pending_state == MM_PLAYER_STATE_NONE) {
516 if (current_state == MM_PLAYER_STATE_PLAYING)
518 else if (current_state != MM_PLAYER_STATE_PAUSED)
520 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
522 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
523 LOGD("player is going to paused state, just change the pending state as playing");
533 player->cmd = command;
535 return MM_ERROR_NONE;
538 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
539 MMPLAYER_STATE_GET_NAME(current_state), command);
540 return MM_ERROR_PLAYER_INVALID_STATE;
543 LOGW("not completed seek");
544 return MM_ERROR_PLAYER_DOING_SEEK;
547 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
548 return MM_ERROR_PLAYER_NO_OP;
551 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
552 return MM_ERROR_PLAYER_NO_OP;
555 static int __mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
557 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
558 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
561 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
562 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
564 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
565 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
567 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
568 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
571 LOGE("invalid mmplayer resource type %d", type);
572 return MM_ERROR_PLAYER_INTERNAL;
575 if (player->hw_resource[type] != NULL) {
576 LOGD("[%d type] resource was already acquired", type);
577 return MM_ERROR_NONE;
580 LOGD("mark for acquire [%d type] resource", type);
581 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
582 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
583 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
584 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
585 return MM_ERROR_PLAYER_INTERNAL;
588 rm_ret = mm_resource_manager_commit(player->resource_manager);
589 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
590 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
591 return MM_ERROR_PLAYER_INTERNAL;
595 return MM_ERROR_NONE;
598 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
600 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
604 if (player->hw_resource[type] == NULL) {
605 LOGD("there is no acquired [%d type] resource", type);
606 return MM_ERROR_NONE;
609 LOGD("mark for release [%d type] resource", type);
610 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
611 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
612 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
613 return MM_ERROR_PLAYER_INTERNAL;
616 player->hw_resource[type] = NULL;
618 rm_ret = mm_resource_manager_commit(player->resource_manager);
619 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
620 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
621 return MM_ERROR_PLAYER_INTERNAL;
625 return MM_ERROR_NONE;
629 __mmplayer_initialize_gapless_play(mmplayer_t *player)
635 player->smooth_streaming = FALSE;
636 player->videodec_linked = 0;
637 player->audiodec_linked = 0;
638 player->textsink_linked = 0;
639 player->is_external_subtitle_present = FALSE;
640 player->is_external_subtitle_added_now = FALSE;
641 player->not_supported_codec = MISSING_PLUGIN_NONE;
642 player->can_support_codec = FOUND_PLUGIN_NONE;
643 player->pending_seek.is_pending = false;
644 player->pending_seek.pos = 0;
645 player->msg_posted = FALSE;
646 player->has_many_types = FALSE;
647 player->no_more_pad = FALSE;
648 player->not_found_demuxer = 0;
649 player->seek_state = MMPLAYER_SEEK_NONE;
650 player->is_subtitle_force_drop = FALSE;
651 player->play_subtitle = FALSE;
652 player->adjust_subtitle_pos = 0;
654 player->total_bitrate = 0;
655 player->total_maximum_bitrate = 0;
657 _mmplayer_track_initialize(player);
658 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
660 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
661 player->bitrate[i] = 0;
662 player->maximum_bitrate[i] = 0;
665 if (player->v_stream_caps) {
666 gst_caps_unref(player->v_stream_caps);
667 player->v_stream_caps = NULL;
670 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
672 /* clean found audio decoders */
673 if (player->audio_decoders) {
674 GList *a_dec = player->audio_decoders;
675 for (; a_dec; a_dec = g_list_next(a_dec)) {
676 gchar *name = a_dec->data;
677 MMPLAYER_FREEIF(name);
679 g_list_free(player->audio_decoders);
680 player->audio_decoders = NULL;
683 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
689 __mmplayer_gapless_play_thread(gpointer data)
691 mmplayer_t *player = (mmplayer_t *)data;
692 mmplayer_gst_element_t *mainbin = NULL;
694 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
696 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
697 while (!player->gapless_play_thread_exit) {
698 LOGD("gapless play thread started. waiting for signal.");
699 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
701 LOGD("reconfigure pipeline for gapless play.");
703 if (player->gapless_play_thread_exit) {
704 if (player->gapless.reconfigure) {
705 player->gapless.reconfigure = false;
706 MMPLAYER_PLAYBACK_UNLOCK(player);
708 LOGD("exiting gapless play thread");
712 mainbin = player->pipeline->mainbin;
714 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
715 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
716 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
717 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
718 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
720 /* Initialize Player values */
721 __mmplayer_initialize_gapless_play(player);
723 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
725 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
731 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
733 GSource *source = NULL;
737 source = g_main_context_find_source_by_id(context, source_id);
738 if (source != NULL) {
739 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
740 g_source_destroy(source);
747 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
749 mmplayer_t *player = (mmplayer_t *)hplayer;
750 GstMessage *msg = NULL;
751 GQueue *queue = NULL;
754 MMPLAYER_RETURN_IF_FAIL(player);
756 /* disconnecting bus watch */
757 if (player->bus_watcher)
758 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
759 player->bus_watcher = 0;
761 /* destroy the gst bus msg thread */
762 if (player->bus_msg_thread) {
763 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
764 player->bus_msg_thread_exit = TRUE;
765 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
766 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
768 LOGD("gst bus msg thread exit.");
769 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
770 player->bus_msg_thread = NULL;
772 g_mutex_clear(&player->bus_msg_thread_mutex);
773 g_cond_clear(&player->bus_msg_thread_cond);
776 g_mutex_lock(&player->bus_msg_q_lock);
777 queue = player->bus_msg_q;
778 while (!g_queue_is_empty(queue)) {
779 msg = (GstMessage *)g_queue_pop_head(queue);
784 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
785 gst_message_unref(msg);
787 g_mutex_unlock(&player->bus_msg_q_lock);
793 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
795 GstElement *parent = NULL;
797 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
798 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
801 MMPLAYER_FSINK_LOCK(player);
803 /* get parent of fakesink */
804 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
806 LOGD("fakesink already removed");
810 gst_element_set_locked_state(fakesink->gst, TRUE);
812 /* setting the state to NULL never returns async
813 * so no need to wait for completion of state transiton
815 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
816 LOGE("fakesink state change failure!");
817 /* FIXIT : should I return here? or try to proceed to next? */
820 /* remove fakesink from it's parent */
821 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
822 LOGE("failed to remove fakesink");
824 gst_object_unref(parent);
829 gst_object_unref(parent);
831 LOGD("state-holder removed");
833 gst_element_set_locked_state(fakesink->gst, FALSE);
835 MMPLAYER_FSINK_UNLOCK(player);
840 gst_element_set_locked_state(fakesink->gst, FALSE);
842 MMPLAYER_FSINK_UNLOCK(player);
846 static GstPadProbeReturn
847 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
849 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
850 return GST_PAD_PROBE_OK;
854 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
856 gint64 stop_running_time = 0;
857 gint64 position_running_time = 0;
861 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
862 if ((player->gapless.update_segment[idx] == TRUE) ||
863 !(player->selector[idx].event_probe_id)) {
865 LOGW("[%d] skip", idx);
870 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
872 gst_segment_to_running_time(&player->gapless.segment[idx],
873 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
874 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
876 gst_segment_to_running_time(&player->gapless.segment[idx],
877 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
879 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
881 gst_segment_to_running_time(&player->gapless.segment[idx],
882 GST_FORMAT_TIME, player->duration);
885 position_running_time =
886 gst_segment_to_running_time(&player->gapless.segment[idx],
887 GST_FORMAT_TIME, player->gapless.segment[idx].position);
889 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
890 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
892 GST_TIME_ARGS(stop_running_time),
893 GST_TIME_ARGS(position_running_time),
894 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
895 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
897 position_running_time = MAX(position_running_time, stop_running_time);
898 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
899 GST_FORMAT_TIME, player->gapless.segment[idx].start);
900 position_running_time = MAX(0, position_running_time);
901 position = MAX(position, position_running_time);
905 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
906 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
907 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
909 player->gapless.start_time[stream_type] += position;
915 static GstPadProbeReturn
916 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
918 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
919 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
920 mmplayer_t *player = (mmplayer_t *)data;
921 GstCaps *caps = NULL;
922 GstStructure *str = NULL;
923 const gchar *name = NULL;
924 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
925 gboolean caps_ret = TRUE;
927 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
928 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
929 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
930 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
931 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
934 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
938 if (strstr(name, "audio")) {
939 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
940 } else if (strstr(name, "video")) {
941 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
943 /* text track is not supportable */
944 LOGE("invalid name %s", name);
948 switch (GST_EVENT_TYPE(event)) {
951 /* in case of gapless, drop eos event not to send it to sink */
952 if (player->gapless.reconfigure && !player->msg_posted) {
953 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
954 ret = GST_PAD_PROBE_DROP;
958 case GST_EVENT_STREAM_START:
960 __mmplayer_gst_selector_update_start_time(player, stream_type);
963 case GST_EVENT_FLUSH_STOP:
965 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
966 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
967 player->gapless.start_time[stream_type] = 0;
970 case GST_EVENT_SEGMENT:
975 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
976 gst_event_copy_segment(event, &segment);
978 if (segment.format != GST_FORMAT_TIME)
981 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
982 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
983 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
984 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
985 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
986 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
988 /* keep the all the segment ev to cover the seeking */
989 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
990 player->gapless.update_segment[stream_type] = TRUE;
992 if (!player->gapless.running)
995 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
997 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
999 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1000 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1001 gst_event_unref(event);
1002 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1008 gdouble proportion = 0.0;
1009 GstClockTimeDiff diff = 0;
1010 GstClockTime timestamp = 0;
1011 gint64 running_time_diff = -1;
1012 GstQOSType type = 0;
1013 GstEvent *tmpev = NULL;
1015 running_time_diff = player->gapless.segment[stream_type].base;
1017 if (running_time_diff <= 0) /* don't need to adjust */
1020 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1021 gst_event_unref(event);
1023 if (timestamp < running_time_diff) {
1024 LOGW("QOS event from previous group");
1025 ret = GST_PAD_PROBE_DROP;
1030 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1031 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1032 stream_type, GST_TIME_ARGS(timestamp),
1033 GST_TIME_ARGS(running_time_diff),
1034 GST_TIME_ARGS(timestamp - running_time_diff));
1037 timestamp -= running_time_diff;
1039 /* That case is invalid for QoS events */
1040 if (diff < 0 && -diff > timestamp) {
1041 LOGW("QOS event from previous group");
1042 ret = GST_PAD_PROBE_DROP;
1046 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1047 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1057 gst_caps_unref(caps);
1061 /* create fakesink for audio or video path witout audiobin or videobin */
1063 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1065 GstElement *pipeline = NULL;
1066 GstElement *fakesink = NULL;
1067 GstPad *sinkpad = NULL;
1070 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1072 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1075 fakesink = gst_element_factory_make("fakesink", NULL);
1076 if (fakesink == NULL) {
1077 LOGE("failed to create fakesink");
1081 /* store it as it's sink element */
1082 __mmplayer_add_sink(player, fakesink);
1084 gst_bin_add(GST_BIN(pipeline), fakesink);
1087 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1089 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1091 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1092 LOGE("failed to link fakesink");
1093 gst_object_unref(GST_OBJECT(fakesink));
1097 if (strstr(name, "video")) {
1098 if (player->v_stream_caps) {
1099 gst_caps_unref(player->v_stream_caps);
1100 player->v_stream_caps = NULL;
1102 if (player->ini.set_dump_element_flag)
1103 __mmplayer_add_dump_buffer_probe(player, fakesink);
1106 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1107 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1111 gst_object_unref(GST_OBJECT(sinkpad));
1118 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1120 GstElement *pipeline = NULL;
1121 GstElement *selector = NULL;
1122 GstPad *srcpad = NULL;
1125 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1127 selector = gst_element_factory_make("input-selector", NULL);
1129 LOGE("failed to create input-selector");
1132 g_object_set(selector, "sync-streams", TRUE, NULL);
1134 player->pipeline->mainbin[elem_idx].id = elem_idx;
1135 player->pipeline->mainbin[elem_idx].gst = selector;
1137 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1139 srcpad = gst_element_get_static_pad(selector, "src");
1141 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1142 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1143 __mmplayer_gst_selector_blocked, NULL, NULL);
1144 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1145 __mmplayer_gst_selector_event_probe, player, NULL);
1147 gst_element_set_state(selector, GST_STATE_PAUSED);
1149 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1150 gst_bin_add(GST_BIN(pipeline), selector);
1152 gst_object_unref(GST_OBJECT(srcpad));
1159 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1161 mmplayer_t *player = (mmplayer_t *)data;
1162 GstElement *selector = NULL;
1163 GstCaps *caps = NULL;
1164 GstStructure *str = NULL;
1165 const gchar *name = NULL;
1166 GstPad *sinkpad = NULL;
1167 gboolean first_track = FALSE;
1168 gboolean caps_ret = TRUE;
1170 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1171 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1174 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1175 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1177 LOGD("pad-added signal handling");
1179 /* get mimetype from caps */
1180 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1184 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1186 LOGD("detected mimetype : %s", name);
1189 if (strstr(name, "video")) {
1191 gchar *caps_str = NULL;
1193 caps_str = gst_caps_to_string(caps);
1194 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1195 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1196 player->set_mode.video_zc = true;
1198 MMPLAYER_FREEIF(caps_str);
1200 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1201 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1203 LOGD("surface type : %d", stype);
1205 if (MMPLAYER_IS_MS_BUFF_SRC(player) || MMPLAYER_USE_URIDECODEBIN3(player)) {
1206 __mmplayer_gst_create_sinkbin(elem, pad, player);
1210 /* in case of exporting video frame, it requires the 360 video filter.
1211 * it will be handled in _no_more_pads(). */
1212 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1213 __mmplayer_gst_make_fakesink(player, pad, name);
1217 LOGD("video selector is required");
1218 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1219 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1220 } else if (strstr(name, "audio")) {
1221 gint samplerate = 0;
1224 if (MMPLAYER_IS_MS_BUFF_SRC(player) || MMPLAYER_USE_URIDECODEBIN3(player) || player->build_audio_offload) {
1225 if (player->build_audio_offload)
1226 player->no_more_pad = TRUE; /* remove state holder */
1227 __mmplayer_gst_create_sinkbin(elem, pad, player);
1231 gst_structure_get_int(str, "rate", &samplerate);
1232 gst_structure_get_int(str, "channels", &channels);
1234 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1235 __mmplayer_gst_make_fakesink(player, pad, name);
1239 LOGD("audio selector is required");
1240 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1241 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1243 } else if (strstr(name, "text")) {
1244 LOGD("text selector is required");
1245 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1246 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1248 LOGE("invalid caps info");
1252 /* check selector and create it */
1253 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1254 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1259 LOGD("input-selector is already created.");
1263 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1265 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1267 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1268 LOGE("failed to link selector");
1269 gst_object_unref(GST_OBJECT(selector));
1274 LOGD("this track will be activated");
1275 g_object_set(selector, "active-pad", sinkpad, NULL);
1278 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1284 gst_caps_unref(caps);
1287 gst_object_unref(GST_OBJECT(sinkpad));
1295 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1297 GstPad *srcpad = NULL;
1300 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1302 LOGD("type %d", type);
1305 LOGD("there is no %d track", type);
1309 srcpad = gst_element_get_static_pad(selector, "src");
1311 LOGE("failed to get srcpad from selector");
1315 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1317 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1319 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1320 if (player->selector[type].block_id) {
1321 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1322 player->selector[type].block_id = 0;
1326 gst_object_unref(GST_OBJECT(srcpad));
1335 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1337 gint active_index = 0;
1340 MMPLAYER_RETURN_IF_FAIL(player);
1342 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1344 /* change track to active pad */
1345 active_index = player->selector[type].active_pad_index;
1346 if ((active_index != DEFAULT_TRACK) &&
1347 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1348 LOGW("failed to change %d type track to %d", type, active_index);
1349 player->selector[type].active_pad_index = DEFAULT_TRACK;
1353 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1354 mm_player_set_attribute((MMHandleType)player, NULL,
1355 "content_text_track_num", player->selector[type].total_track_num,
1356 "current_text_track_index", player->selector[type].active_pad_index, NULL);
1363 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1366 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1368 if (!audio_selector) {
1369 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1371 /* in case the source is changed, output can be changed. */
1372 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1373 LOGD("remove previous audiobin if it exist");
1375 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1376 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1378 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1379 MMPLAYER_FREEIF(player->pipeline->audiobin);
1382 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1383 _mmplayer_pipeline_complete(NULL, player);
1388 /* apply the audio track information */
1389 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1391 /* create audio sink path */
1392 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1393 LOGE("failed to create audio sink path");
1402 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1405 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1407 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1408 LOGD("text path is not supproted");
1412 /* apply the text track information */
1413 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1415 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1416 player->has_closed_caption = TRUE;
1418 /* create text decode path */
1419 player->no_more_pad = TRUE;
1421 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1422 LOGE("failed to create text sink path");
1431 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1433 gint64 dur_bytes = 0L;
1436 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1437 player->pipeline->mainbin && player->streamer, FALSE);
1439 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1440 LOGE("fail to get duration.");
1442 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1443 * use file information was already set on Q2 when it was created. */
1444 _mm_player_streaming_set_queue2(player->streamer,
1445 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1446 TRUE, /* use_buffering */
1447 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1448 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1455 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1457 mmplayer_t *player = NULL;
1458 GstElement *video_selector = NULL;
1459 GstElement *audio_selector = NULL;
1460 GstElement *text_selector = NULL;
1463 player = (mmplayer_t *)data;
1465 LOGD("no-more-pad signal handling");
1467 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1468 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1469 LOGW("player is shutting down");
1473 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1474 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1475 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1476 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1477 LOGE("failed to set queue2 buffering");
1482 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1483 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1484 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1486 if (!video_selector && !audio_selector && !text_selector) {
1487 LOGW("there is no selector");
1488 player->no_more_pad = TRUE;
1492 /* create video path followed by video-select */
1493 if (video_selector && !audio_selector && !text_selector)
1494 player->no_more_pad = TRUE;
1496 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1499 /* create audio path followed by audio-select */
1500 if (audio_selector && !text_selector)
1501 player->no_more_pad = TRUE;
1503 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1506 /* create text path followed by text-select */
1507 __mmplayer_create_text_sink_path(player, text_selector);
1510 if (player->gapless.reconfigure) {
1511 player->gapless.reconfigure = FALSE;
1512 MMPLAYER_PLAYBACK_UNLOCK(player);
1519 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1521 gboolean ret = FALSE;
1522 GstElement *pipeline = NULL;
1523 GstPad *sinkpad = NULL;
1526 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1527 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1529 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1531 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1533 LOGE("failed to get pad from sinkbin");
1539 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1540 LOGE("failed to link sinkbin for reusing");
1541 goto EXIT; /* exit either pass or fail */
1545 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1546 LOGE("failed to set state(READY) to sinkbin");
1551 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1552 LOGE("failed to add sinkbin to pipeline");
1557 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1558 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1563 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1564 LOGE("failed to set state(PAUSED) to sinkbin");
1573 gst_object_unref(GST_OBJECT(sinkpad));
1581 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1583 mmplayer_t *player = NULL;
1584 GstCaps *caps = NULL;
1585 gchar *caps_str = NULL;
1586 GstStructure *str = NULL;
1587 const gchar *name = NULL;
1588 GstElement *sinkbin = NULL;
1589 gboolean reusing = FALSE;
1590 gboolean caps_ret = TRUE;
1591 gchar *sink_pad_name = "sink";
1594 player = (mmplayer_t *)data;
1597 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1598 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1600 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1604 caps_str = gst_caps_to_string(caps);
1606 LOGD("detected mimetype : %s", name);
1608 if (strstr(name, "audio")) {
1609 if (player->pipeline->audiobin == NULL) {
1610 const gchar *audio_format = gst_structure_get_string(str, "format");
1612 LOGD("original audio format %s", audio_format);
1613 mm_player_set_attribute((MMHandleType)player, NULL,
1614 "content_audio_format", audio_format, strlen(audio_format), NULL);
1617 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1618 LOGE("failed to create audiobin. continuing without audio");
1622 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1623 LOGD("creating audiobin success");
1626 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1627 LOGD("reusing audiobin");
1628 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1630 } else if (strstr(name, "video")) {
1631 /* 1. zero copy is updated at _decode_pad_added()
1632 * 2. NULL surface type is handled in _decode_pad_added() */
1633 LOGD("zero copy %d", player->set_mode.video_zc);
1634 if (player->pipeline->videobin == NULL) {
1635 int surface_type = 0;
1636 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1637 LOGD("display_surface_type (%d)", surface_type);
1639 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1640 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1641 LOGE("failed to acquire video overlay resource");
1645 player->interrupted_by_resource = FALSE;
1647 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1648 LOGE("failed to create videobin. continuing without video");
1652 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1653 LOGD("creating videosink bin success");
1656 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1657 LOGD("re-using videobin");
1658 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1660 } else if (strstr(name, "text")) {
1661 if (player->pipeline->textbin == NULL) {
1662 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1663 LOGE("failed to create text sink bin. continuing without text");
1667 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1668 player->textsink_linked = 1;
1669 LOGD("creating textsink bin success");
1671 if (!player->textsink_linked) {
1672 LOGD("re-using textbin");
1674 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1675 player->textsink_linked = 1;
1677 /* linked textbin exist which means that the external subtitle path exist already */
1678 LOGW("ignoring internal subtutle since external subtitle is available");
1681 sink_pad_name = "text_sink";
1683 LOGW("unknown mime type %s, ignoring it", name);
1687 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1690 LOGD("[handle: %p] success to create and link sink bin", player);
1692 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1693 * streaming task. if the task blocked, then buffer will not flow to the next element
1694 *(autoplugging element). so this is special hack for streaming. please try to remove it
1696 /* dec stream count. we can remove fakesink if it's zero */
1697 if (player->num_dynamic_pad)
1698 player->num_dynamic_pad--;
1700 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1702 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1703 _mmplayer_pipeline_complete(NULL, player);
1707 MMPLAYER_FREEIF(caps_str);
1710 gst_caps_unref(caps);
1716 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1718 int required_angle = 0; /* Angle required for straight view */
1719 int rotation_angle = 0;
1721 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1722 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1724 /* Counter clockwise */
1725 switch (orientation) {
1730 required_angle = 270;
1733 required_angle = 180;
1736 required_angle = 90;
1740 rotation_angle = display_angle + required_angle;
1741 if (rotation_angle >= 360)
1742 rotation_angle -= 360;
1744 /* chech if supported or not */
1745 if (rotation_angle % 90) {
1746 LOGD("not supported rotation angle = %d", rotation_angle);
1750 switch (rotation_angle) {
1752 *value = MM_DISPLAY_ROTATION_NONE;
1755 *value = MM_DISPLAY_ROTATION_90;
1758 *value = MM_DISPLAY_ROTATION_180;
1761 *value = MM_DISPLAY_ROTATION_270;
1765 LOGD("setting rotation property value : %d", *value);
1771 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1773 int display_rotation = 0;
1774 gchar *org_orient = NULL;
1775 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1778 LOGE("cannot get content attribute");
1779 return MM_ERROR_PLAYER_INTERNAL;
1782 if (display_angle) {
1783 /* update user roation */
1784 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1786 /* Counter clockwise */
1787 switch (display_rotation) {
1788 case MM_DISPLAY_ROTATION_NONE:
1791 case MM_DISPLAY_ROTATION_90:
1792 *display_angle = 90;
1794 case MM_DISPLAY_ROTATION_180:
1795 *display_angle = 180;
1797 case MM_DISPLAY_ROTATION_270:
1798 *display_angle = 270;
1801 LOGW("wrong angle type : %d", display_rotation);
1804 LOGD("check user angle: %d", *display_angle);
1808 /* Counter clockwise */
1809 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1812 if (!strcmp(org_orient, "rotate-90"))
1814 else if (!strcmp(org_orient, "rotate-180"))
1816 else if (!strcmp(org_orient, "rotate-270"))
1819 LOGD("original rotation is %s", org_orient);
1821 LOGD("content_video_orientation get fail");
1824 LOGD("check orientation: %d", *orientation);
1827 return MM_ERROR_NONE;
1830 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1832 int rotation_value = 0;
1833 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1834 int display_angle = 0;
1837 /* check video sinkbin is created */
1838 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1841 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1843 /* get rotation value to set */
1844 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1845 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1846 LOGD("set video param : rotate %d", rotation_value);
1849 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1851 MMHandleType attrs = 0;
1855 /* check video sinkbin is created */
1856 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1859 attrs = MMPLAYER_GET_ATTRS(player);
1860 MMPLAYER_RETURN_IF_FAIL(attrs);
1862 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1863 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1864 LOGD("set video param : visible %d", visible);
1867 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1869 MMHandleType attrs = 0;
1870 int display_method = 0;
1873 /* check video sinkbin is created */
1874 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1877 attrs = MMPLAYER_GET_ATTRS(player);
1878 MMPLAYER_RETURN_IF_FAIL(attrs);
1880 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1881 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1882 LOGD("set video param : method %d", display_method);
1885 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1887 MMHandleType attrs = 0;
1891 /* check video sinkbin is created */
1892 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1895 attrs = MMPLAYER_GET_ATTRS(player);
1896 MMPLAYER_RETURN_IF_FAIL(attrs);
1898 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1899 MMPLAYER_RETURN_IF_FAIL(handle);
1901 gst_video_overlay_set_video_roi_area(
1902 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1903 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1904 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1905 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1908 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1910 MMHandleType attrs = 0;
1915 int win_roi_width = 0;
1916 int win_roi_height = 0;
1919 /* check video sinkbin is created */
1920 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1923 attrs = MMPLAYER_GET_ATTRS(player);
1924 MMPLAYER_RETURN_IF_FAIL(attrs);
1926 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1927 MMPLAYER_RETURN_IF_FAIL(handle);
1929 /* It should be set after setting window */
1930 mm_attrs_multiple_get(attrs, NULL,
1931 "display_win_roi_x", &win_roi_x,
1932 "display_win_roi_y", &win_roi_y,
1933 "display_win_roi_width", &win_roi_width,
1934 "display_win_roi_height", &win_roi_height, NULL);
1936 /* After setting window handle, set display roi area */
1937 gst_video_overlay_set_display_roi_area(
1938 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1939 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1940 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1941 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1944 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1946 MMHandleType attrs = 0;
1949 /* check video sinkbin is created */
1950 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1953 attrs = MMPLAYER_GET_ATTRS(player);
1954 MMPLAYER_RETURN_IF_FAIL(attrs);
1956 /* common case if using overlay surface */
1957 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1958 MMPLAYER_RETURN_IF_FAIL(handle);
1960 /* default is using wl_surface_id */
1961 LOGD("set video param : wl_surface_id %d", handle);
1962 gst_video_overlay_set_wl_window_wl_surface_id(
1963 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1968 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
1970 gboolean update_all_param = FALSE;
1974 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
1975 LOGW("videosink is not ready yet");
1976 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1979 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1980 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
1981 return MM_ERROR_PLAYER_INTERNAL;
1984 LOGD("param_name : %s", param_name);
1985 if (!g_strcmp0(param_name, "update_all_param"))
1986 update_all_param = TRUE;
1988 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1989 __mmplayer_video_param_set_display_overlay(player);
1990 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1991 __mmplayer_video_param_set_display_method(player);
1992 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1993 __mmplayer_video_param_set_display_visible(player);
1994 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1995 __mmplayer_video_param_set_display_rotation(player);
1996 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
1997 __mmplayer_video_param_set_roi_area(player);
1998 if (update_all_param)
1999 __mmplayer_video_param_set_video_roi_area(player);
2003 return MM_ERROR_NONE;
2007 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2009 gboolean disable_overlay = FALSE;
2010 mmplayer_t *player = (mmplayer_t *)hplayer;
2013 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2014 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2015 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2016 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2018 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2019 LOGW("Display control is not supported");
2020 return MM_ERROR_PLAYER_INTERNAL;
2023 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2025 if (audio_only == (bool)disable_overlay) {
2026 LOGE("It's the same with current setting: (%d)", audio_only);
2027 return MM_ERROR_NONE;
2031 LOGE("disable overlay");
2032 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2034 /* release overlay resource */
2035 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2036 LOGE("failed to release overlay resource");
2040 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2041 LOGE("failed to acquire video overlay resource");
2044 player->interrupted_by_resource = FALSE;
2046 LOGD("enable overlay");
2047 __mmplayer_video_param_set_display_overlay(player);
2048 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2053 return MM_ERROR_NONE;
2057 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2059 mmplayer_t *player = (mmplayer_t *)hplayer;
2060 gboolean disable_overlay = FALSE;
2064 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2065 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2066 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2067 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2068 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2070 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2071 LOGW("Display control is not supported");
2072 return MM_ERROR_PLAYER_INTERNAL;
2075 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2077 *paudio_only = (bool)disable_overlay;
2079 LOGD("audio_only : %d", *paudio_only);
2083 return MM_ERROR_NONE;
2087 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2089 GList *bucket = element_bucket;
2090 mmplayer_gst_element_t *element = NULL;
2091 mmplayer_gst_element_t *prv_element = NULL;
2092 GstElement *tee_element = NULL;
2093 gint successful_link_count = 0;
2097 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2099 prv_element = (mmplayer_gst_element_t *)bucket->data;
2100 bucket = bucket->next;
2102 for (; bucket; bucket = bucket->next) {
2103 element = (mmplayer_gst_element_t *)bucket->data;
2105 if (element && element->gst) {
2106 if (prv_element && prv_element->gst) {
2107 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2109 prv_element->gst = tee_element;
2111 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2112 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2113 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2117 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2118 LOGD("linking [%s] to [%s] success",
2119 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2120 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2121 successful_link_count++;
2122 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2123 LOGD("keep audio-tee element for next audio pipeline branch");
2124 tee_element = prv_element->gst;
2127 LOGD("linking [%s] to [%s] failed",
2128 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2129 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2135 prv_element = element;
2140 return successful_link_count;
2144 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2146 GList *bucket = element_bucket;
2147 mmplayer_gst_element_t *element = NULL;
2148 int successful_add_count = 0;
2152 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2153 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2155 for (; bucket; bucket = bucket->next) {
2156 element = (mmplayer_gst_element_t *)bucket->data;
2158 if (element && element->gst) {
2159 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2160 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2161 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2162 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2165 successful_add_count++;
2171 return successful_add_count;
2175 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2177 mmplayer_t *player = (mmplayer_t *)data;
2178 GstCaps *caps = NULL;
2179 GstStructure *str = NULL;
2181 gboolean caps_ret = TRUE;
2185 MMPLAYER_RETURN_IF_FAIL(pad);
2186 MMPLAYER_RETURN_IF_FAIL(unused);
2187 MMPLAYER_RETURN_IF_FAIL(data);
2189 caps = gst_pad_get_current_caps(pad);
2193 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2197 LOGD("name = %s", name);
2199 if (strstr(name, "audio")) {
2200 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2202 if (player->audio_stream_changed_cb) {
2203 LOGE("call the audio stream changed cb");
2204 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2206 } else if (strstr(name, "video")) {
2207 if ((name = gst_structure_get_string(str, "format")))
2208 player->set_mode.video_zc = name[0] == 'S';
2210 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2211 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2213 LOGW("invalid caps info");
2218 gst_caps_unref(caps);
2226 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2231 MMPLAYER_RETURN_IF_FAIL(player);
2233 if (player->audio_stream_buff_list) {
2234 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2235 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2238 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2239 __mmplayer_audio_stream_send_data(player, tmp);
2241 MMPLAYER_FREEIF(tmp->pcm_data);
2242 MMPLAYER_FREEIF(tmp);
2245 g_list_free(player->audio_stream_buff_list);
2246 player->audio_stream_buff_list = NULL;
2253 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2255 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2258 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2260 audio_stream.bitrate = a_buffer->bitrate;
2261 audio_stream.channel = a_buffer->channel;
2262 audio_stream.channel_mask = a_buffer->channel_mask;
2263 audio_stream.data_size = a_buffer->data_size;
2264 audio_stream.data = a_buffer->pcm_data;
2265 audio_stream.pcm_format = a_buffer->pcm_format;
2267 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2269 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2275 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2277 mmplayer_t *player = (mmplayer_t *)data;
2278 const gchar *pcm_format = NULL;
2281 guint64 channel_mask = 0;
2282 void *a_data = NULL;
2284 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2285 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2289 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2291 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2292 a_data = mapinfo.data;
2293 a_size = mapinfo.size;
2295 GstCaps *caps = gst_pad_get_current_caps(pad);
2296 GstStructure *structure = gst_caps_get_structure(caps, 0);
2298 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2300 pcm_format = gst_structure_get_string(structure, "format");
2301 gst_structure_get_int(structure, "rate", &rate);
2302 gst_structure_get_int(structure, "channels", &channel);
2303 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2304 gst_caps_unref(GST_CAPS(caps));
2306 /* In case of the sync is false, use buffer list. *
2307 * The num of buffer list depends on the num of audio channels */
2308 if (player->audio_stream_buff_list) {
2309 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2310 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2312 if (channel_mask == tmp->channel_mask) {
2314 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2316 if (tmp->data_size + a_size < tmp->buff_size) {
2317 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2318 tmp->data_size += a_size;
2320 /* send data to client */
2321 __mmplayer_audio_stream_send_data(player, tmp);
2323 if (a_size > tmp->buff_size) {
2324 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2325 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2326 if (tmp->pcm_data == NULL) {
2327 LOGE("failed to realloc data.");
2330 tmp->buff_size = a_size;
2332 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2333 memcpy(tmp->pcm_data, a_data, a_size);
2334 tmp->data_size = a_size;
2339 LOGE("data is empty in list.");
2345 /* create new audio stream data for newly found audio channel */
2346 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2347 if (a_buffer == NULL) {
2348 LOGE("failed to alloc data.");
2351 a_buffer->bitrate = rate;
2352 a_buffer->channel = channel;
2353 a_buffer->channel_mask = channel_mask;
2354 a_buffer->data_size = a_size;
2355 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2357 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2358 /* If sync is FALSE, use buffer list to reduce the IPC. */
2359 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2360 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2361 if (a_buffer->pcm_data == NULL) {
2362 LOGE("failed to alloc data.");
2363 MMPLAYER_FREEIF(a_buffer);
2366 memcpy(a_buffer->pcm_data, a_data, a_size);
2368 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2370 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2372 /* If sync is TRUE, send data directly. */
2373 a_buffer->pcm_data = a_data;
2374 __mmplayer_audio_stream_send_data(player, a_buffer);
2375 MMPLAYER_FREEIF(a_buffer);
2379 gst_buffer_unmap(buffer, &mapinfo);
2384 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2386 mmplayer_t *player = (mmplayer_t *)data;
2387 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2388 GstPad *sinkpad = NULL;
2389 GstElement *queue = NULL, *sink = NULL;
2392 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2394 queue = gst_element_factory_make("queue", NULL);
2395 if (queue == NULL) {
2396 LOGD("fail make queue");
2400 sink = gst_element_factory_make("fakesink", NULL);
2402 LOGD("fail make fakesink");
2406 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2408 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2409 LOGW("failed to link queue & sink");
2413 sinkpad = gst_element_get_static_pad(queue, "sink");
2415 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2416 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2420 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2422 gst_object_unref(sinkpad);
2423 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2424 g_object_set(sink, "sync", TRUE, NULL);
2425 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2427 /* keep the first sink reference only */
2428 if (!audiobin[MMPLAYER_A_SINK].gst) {
2429 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2430 audiobin[MMPLAYER_A_SINK].gst = sink;
2434 _mmplayer_add_signal_connection(player,
2436 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2438 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2441 __mmplayer_add_sink(player, sink);
2443 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2444 LOGE("failed to sync state");
2448 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2449 LOGE("failed to sync state");
2457 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2459 gst_object_unref(GST_OBJECT(queue));
2463 gst_object_unref(GST_OBJECT(sink));
2467 gst_object_unref(GST_OBJECT(sinkpad));
2475 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2477 mmplayer_t *player = (mmplayer_t *)data;
2480 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2482 player->no_more_pad = TRUE;
2483 _mmplayer_pipeline_complete(NULL, player);
2490 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2492 #define MAX_PROPS_LEN 128
2493 mmplayer_gst_element_t *audiobin = NULL;
2494 gint latency_mode = 0;
2495 gchar *stream_type = NULL;
2496 gchar *latency = NULL;
2498 gchar stream_props[MAX_PROPS_LEN] = {0,};
2499 GstStructure *props = NULL;
2502 * It should be set after player creation through attribute.
2503 * But, it can not be changed during playing.
2506 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2508 audiobin = player->pipeline->audiobin;
2510 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2511 if (player->sound.mute) {
2512 LOGD("mute enabled");
2513 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2516 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2517 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2520 snprintf(stream_props, sizeof(stream_props) - 1,
2521 "props,application.process.id.origin=%d", player->client_pid);
2523 snprintf(stream_props, sizeof(stream_props) - 1,
2524 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2525 stream_type, stream_id, player->client_pid);
2527 props = gst_structure_from_string(stream_props, NULL);
2528 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2529 LOGI("props result[%s].", stream_props);
2530 gst_structure_free(props);
2532 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2534 switch (latency_mode) {
2535 case AUDIO_LATENCY_MODE_LOW:
2536 latency = g_strndup("low", 3);
2538 case AUDIO_LATENCY_MODE_MID:
2539 latency = g_strndup("mid", 3);
2541 case AUDIO_LATENCY_MODE_HIGH:
2542 latency = g_strndup("high", 4);
2546 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2548 LOGD("audiosink property - latency=%s", latency);
2550 MMPLAYER_FREEIF(latency);
2556 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2558 mmplayer_gst_element_t *audiobin = NULL;
2561 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2563 audiobin = player->pipeline->audiobin;
2565 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2566 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2567 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2569 if (player->video360_yaw_radians <= M_PI &&
2570 player->video360_yaw_radians >= -M_PI &&
2571 player->video360_pitch_radians <= M_PI_2 &&
2572 player->video360_pitch_radians >= -M_PI_2) {
2573 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2574 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2575 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2576 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2577 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2578 "source-orientation-y", player->video360_metadata.init_view_heading,
2579 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2586 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2588 mmplayer_gst_element_t *audiobin = NULL;
2589 GstPad *sink_pad = NULL;
2590 GstCaps *acaps = NULL;
2592 int pitch_control = 0;
2593 double pitch_value = 1.0;
2596 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2597 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2599 audiobin = player->pipeline->audiobin;
2601 LOGD("make element for normal audio playback");
2603 /* audio bin structure for playback. {} means optional.
2604 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2606 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2607 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2610 /* for pitch control */
2611 mm_attrs_multiple_get(player->attrs, NULL,
2612 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2613 MM_PLAYER_PITCH_VALUE, &pitch_value,
2616 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2617 if (pitch_control && (player->videodec_linked == 0)) {
2618 GstElementFactory *factory;
2620 factory = gst_element_factory_find("pitch");
2622 gst_object_unref(factory);
2625 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2628 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2629 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2631 LOGW("there is no pitch element");
2636 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2638 /* replaygain volume */
2639 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2640 if (player->sound.rg_enable)
2641 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2643 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2646 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2648 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2649 /* currently, only openalsink uses volume element */
2650 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2651 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2653 if (player->sound.mute) {
2654 LOGD("mute enabled");
2655 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2659 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2661 /* audio effect element. if audio effect is enabled */
2662 if ((strcmp(player->ini.audioeffect_element, ""))
2664 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2665 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2667 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2669 if ((!player->bypass_audio_effect)
2670 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2671 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2672 if (!_mmplayer_audio_effect_custom_apply(player))
2673 LOGI("apply audio effect(custom) setting success");
2677 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2678 && (player->set_mode.rich_audio)) {
2679 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2683 /* create audio sink */
2684 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2685 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2686 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2688 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2689 if (player->is_360_feature_enabled &&
2690 player->is_content_spherical &&
2692 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2693 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2694 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2696 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2698 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2700 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2701 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2702 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2703 gst_caps_unref(acaps);
2705 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2707 player->is_openal_plugin_used = TRUE;
2709 if (player->is_360_feature_enabled && player->is_content_spherical)
2710 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2711 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2714 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2715 (player->videodec_linked && player->ini.use_system_clock)) {
2716 LOGD("system clock will be used.");
2717 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2720 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2721 __mmplayer_gst_set_pulsesink_property(player);
2722 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2723 __mmplayer_gst_set_openalsink_property(player);
2726 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2727 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2729 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2730 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2731 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2732 gst_object_unref(GST_OBJECT(sink_pad));
2734 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2737 return MM_ERROR_NONE;
2739 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2741 return MM_ERROR_PLAYER_INTERNAL;
2745 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2747 mmplayer_gst_element_t *audiobin = NULL;
2748 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2750 gchar *dst_format = NULL;
2752 int dst_samplerate = 0;
2753 int dst_channels = 0;
2754 GstCaps *caps = NULL;
2755 char *caps_str = NULL;
2758 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2759 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2761 audiobin = player->pipeline->audiobin;
2763 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2765 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2767 [case 1] extract interleave audio pcm without playback
2768 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2769 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2771 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2773 [case 2] deinterleave for each channel without playback
2774 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2775 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2777 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2778 - fakesink (sync or not)
2781 [case 3] [case 1(sync only)] + playback
2782 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2784 * src - ... - tee - queue1 - playback path
2785 - queue2 - [case1 pipeline with sync]
2787 [case 4] [case 2(sync only)] + playback
2788 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2790 * src - ... - tee - queue1 - playback path
2791 - queue2 - [case2 pipeline with sync]
2795 /* 1. create tee and playback path
2796 'tee' should be added at first to copy the decoded stream
2798 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2799 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2800 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2802 /* tee - path 1 : for playback path */
2803 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2804 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2806 /* tee - path 2 : for extract path */
2807 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2808 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2811 /* if there is tee, 'tee - path 2' is linked here */
2813 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2816 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2818 /* 2. decide the extract pcm format */
2819 mm_attrs_multiple_get(player->attrs, NULL,
2820 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2821 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2822 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2825 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2826 dst_format, dst_len, dst_samplerate, dst_channels);
2828 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2829 mm_attrs_multiple_get(player->attrs, NULL,
2830 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2831 "content_audio_samplerate", &dst_samplerate,
2832 "content_audio_channels", &dst_channels,
2835 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2836 dst_format, dst_len, dst_samplerate, dst_channels);
2838 /* If there is no enough information, set it to platform default value. */
2839 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2840 LOGD("set platform default format");
2841 dst_format = DEFAULT_PCM_OUT_FORMAT;
2843 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2844 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2847 /* 3. create capsfilter */
2848 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2849 caps = gst_caps_new_simple("audio/x-raw",
2850 "format", G_TYPE_STRING, dst_format,
2851 "rate", G_TYPE_INT, dst_samplerate,
2852 "channels", G_TYPE_INT, dst_channels,
2855 caps_str = gst_caps_to_string(caps);
2856 LOGD("new caps : %s", caps_str);
2858 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2861 gst_caps_unref(caps);
2862 MMPLAYER_FREEIF(caps_str);
2864 /* 4-1. create deinterleave to extract pcm for each channel */
2865 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2866 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2867 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2869 /* audiosink will be added after getting signal for each channel */
2870 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2871 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2872 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2873 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2874 player->no_more_pad = FALSE;
2876 /* 4-2. create fakesink to extract interlevaed pcm */
2877 LOGD("add audio fakesink for interleaved audio");
2878 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2879 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2880 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2881 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2883 _mmplayer_add_signal_connection(player,
2884 G_OBJECT(audiobin[extract_sink_id].gst),
2885 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2887 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2890 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2894 return MM_ERROR_NONE;
2896 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2898 return MM_ERROR_PLAYER_INTERNAL;
2902 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2904 int ret = MM_ERROR_NONE;
2905 mmplayer_gst_element_t *audiobin = NULL;
2906 GList *element_bucket = NULL;
2909 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2910 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2912 audiobin = player->pipeline->audiobin;
2914 if (player->build_audio_offload) { /* skip all the audio filters */
2915 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2917 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2918 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2919 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2921 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2925 /* FIXME: need to mention the supportable condition at API reference */
2926 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2927 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2929 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2931 if (ret != MM_ERROR_NONE)
2934 LOGD("success to make audio bin element");
2935 *bucket = element_bucket;
2938 return MM_ERROR_NONE;
2941 LOGE("failed to make audio bin element");
2942 g_list_free(element_bucket);
2946 return MM_ERROR_PLAYER_INTERNAL;
2950 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2952 mmplayer_gst_element_t *first_element = NULL;
2953 mmplayer_gst_element_t *audiobin = NULL;
2955 GstPad *ghostpad = NULL;
2956 GList *element_bucket = NULL;
2960 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2963 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2965 LOGE("failed to allocate memory for audiobin");
2966 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2970 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2971 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2972 if (!audiobin[MMPLAYER_A_BIN].gst) {
2973 LOGE("failed to create audiobin");
2978 player->pipeline->audiobin = audiobin;
2980 /* create audio filters and audiosink */
2981 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
2984 /* adding created elements to bin */
2985 LOGD("adding created elements to bin");
2986 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2989 /* linking elements in the bucket by added order. */
2990 LOGD("Linking elements in the bucket by added order.");
2991 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
2994 /* get first element's sinkpad for creating ghostpad */
2995 first_element = (mmplayer_gst_element_t *)element_bucket->data;
2996 if (!first_element) {
2997 LOGE("failed to get first elem");
3001 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3003 LOGE("failed to get pad from first element of audiobin");
3007 ghostpad = gst_ghost_pad_new("sink", pad);
3009 LOGE("failed to create ghostpad");
3013 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3014 LOGE("failed to add ghostpad to audiobin");
3018 gst_object_unref(pad);
3020 g_list_free(element_bucket);
3023 return MM_ERROR_NONE;
3026 LOGD("ERROR : releasing audiobin");
3029 gst_object_unref(GST_OBJECT(pad));
3032 gst_object_unref(GST_OBJECT(ghostpad));
3035 g_list_free(element_bucket);
3037 /* release element which are not added to bin */
3038 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3039 /* NOTE : skip bin */
3040 if (audiobin[i].gst) {
3041 GstObject *parent = NULL;
3042 parent = gst_element_get_parent(audiobin[i].gst);
3045 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3046 audiobin[i].gst = NULL;
3048 gst_object_unref(GST_OBJECT(parent));
3052 /* release audiobin with it's childs */
3053 if (audiobin[MMPLAYER_A_BIN].gst)
3054 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3056 MMPLAYER_FREEIF(audiobin);
3058 player->pipeline->audiobin = NULL;
3060 return MM_ERROR_PLAYER_INTERNAL;
3064 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3066 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3070 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3072 int ret = MM_ERROR_NONE;
3074 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3075 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3077 MMPLAYER_VIDEO_BO_LOCK(player);
3079 if (player->video_bo_list) {
3080 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3081 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3082 if (tmp && tmp->bo == bo) {
3084 LOGD("release bo %p", bo);
3085 tbm_bo_unref(tmp->bo);
3086 MMPLAYER_VIDEO_BO_UNLOCK(player);
3087 MMPLAYER_VIDEO_BO_SIGNAL(player);
3092 /* hw codec is running or the list was reset for DRC. */
3093 LOGW("there is no bo list.");
3095 MMPLAYER_VIDEO_BO_UNLOCK(player);
3097 LOGW("failed to find bo %p", bo);
3102 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3107 MMPLAYER_RETURN_IF_FAIL(player);
3109 MMPLAYER_VIDEO_BO_LOCK(player);
3110 if (player->video_bo_list) {
3111 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3112 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3113 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3116 tbm_bo_unref(tmp->bo);
3120 g_list_free(player->video_bo_list);
3121 player->video_bo_list = NULL;
3123 player->video_bo_size = 0;
3124 MMPLAYER_VIDEO_BO_UNLOCK(player);
3131 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3134 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3135 gboolean ret = TRUE;
3137 /* check DRC, if it is, destroy the prev bo list to create again */
3138 if (player->video_bo_size != size) {
3139 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3140 __mmplayer_video_stream_destroy_bo_list(player);
3141 player->video_bo_size = size;
3144 MMPLAYER_VIDEO_BO_LOCK(player);
3146 if ((!player->video_bo_list) ||
3147 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3149 /* create bo list */
3151 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3153 if (player->video_bo_list) {
3154 /* if bo list did not created all, try it again. */
3155 idx = g_list_length(player->video_bo_list);
3156 LOGD("bo list exist(len: %d)", idx);
3159 for (; idx < player->ini.num_of_video_bo; idx++) {
3160 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3162 LOGE("Fail to alloc bo_info.");
3165 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3167 LOGE("Fail to tbm_bo_alloc.");
3168 MMPLAYER_FREEIF(bo_info);
3171 bo_info->used = FALSE;
3172 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3175 /* update video num buffers */
3176 LOGD("video_num_buffers : %d", idx);
3177 mm_player_set_attribute((MMHandleType)player, NULL,
3178 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3179 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3183 MMPLAYER_VIDEO_BO_UNLOCK(player);
3189 /* get bo from list*/
3190 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3191 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3192 if (tmp && (tmp->used == FALSE)) {
3193 LOGD("found bo %p to use", tmp->bo);
3195 MMPLAYER_VIDEO_BO_UNLOCK(player);
3196 return tbm_bo_ref(tmp->bo);
3200 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3201 MMPLAYER_VIDEO_BO_UNLOCK(player);
3205 if (player->ini.video_bo_timeout <= 0) {
3206 MMPLAYER_VIDEO_BO_WAIT(player);
3208 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3209 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3216 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3218 mmplayer_t *player = (mmplayer_t *)data;
3220 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3222 /* send prerolled pkt */
3223 player->video_stream_prerolled = false;
3225 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3227 /* not to send prerolled pkt again */
3228 player->video_stream_prerolled = true;
3232 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3234 mmplayer_t *player = (mmplayer_t *)data;
3235 mmplayer_video_decoded_data_info_t *stream = NULL;
3236 GstMemory *mem = NULL;
3239 MMPLAYER_RETURN_IF_FAIL(player);
3240 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3242 if (player->video_stream_prerolled) {
3243 player->video_stream_prerolled = false;
3244 LOGD("skip the prerolled pkt not to send it again");
3248 /* clear stream data structure */
3249 stream = __mmplayer_create_stream_from_pad(pad);
3251 LOGE("failed to alloc stream");
3255 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3257 /* set size and timestamp */
3258 mem = gst_buffer_peek_memory(buffer, 0);
3259 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3260 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3262 /* check zero-copy */
3263 if (player->set_mode.video_zc &&
3264 player->set_mode.video_export &&
3265 gst_is_tizen_memory(mem)) {
3266 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3267 stream->internal_buffer = gst_buffer_ref(buffer);
3268 } else { /* sw codec */
3269 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3272 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3276 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3277 LOGE("failed to send video decoded data.");
3284 LOGE("release video stream resource.");
3285 if (gst_is_tizen_memory(mem)) {
3287 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3289 tbm_bo_unref(stream->bo[i]);
3292 /* unref gst buffer */
3293 if (stream->internal_buffer)
3294 gst_buffer_unref(stream->internal_buffer);
3297 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3299 MMPLAYER_FREEIF(stream);
3304 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3306 mmplayer_gst_element_t *videobin = NULL;
3309 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3311 videobin = player->pipeline->videobin;
3313 /* Set spatial media metadata and/or user settings to the element.
3315 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3316 "projection-type", player->video360_metadata.projection_type, NULL);
3318 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3319 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3321 if (player->video360_metadata.full_pano_width_pixels &&
3322 player->video360_metadata.full_pano_height_pixels &&
3323 player->video360_metadata.cropped_area_image_width &&
3324 player->video360_metadata.cropped_area_image_height) {
3325 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3326 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3327 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3328 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3329 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3330 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3331 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3335 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3336 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3337 "horizontal-fov", player->video360_horizontal_fov,
3338 "vertical-fov", player->video360_vertical_fov, NULL);
3341 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3342 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3343 "zoom", 1.0f / player->video360_zoom, NULL);
3346 if (player->video360_yaw_radians <= M_PI &&
3347 player->video360_yaw_radians >= -M_PI &&
3348 player->video360_pitch_radians <= M_PI_2 &&
3349 player->video360_pitch_radians >= -M_PI_2) {
3350 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3351 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3352 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3353 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3354 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3355 "pose-yaw", player->video360_metadata.init_view_heading,
3356 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3359 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3360 "passthrough", !player->is_video360_enabled, NULL);
3367 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3369 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3370 GList *element_bucket = NULL;
3373 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3375 /* create video360 filter */
3376 if (player->is_360_feature_enabled && player->is_content_spherical) {
3377 LOGD("create video360 element");
3378 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3379 __mmplayer_gst_set_video360_property(player);
3383 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3384 LOGD("skip creating the videoconv and rotator");
3385 return MM_ERROR_NONE;
3388 /* in case of sw codec & overlay surface type, except 360 playback.
3389 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3390 LOGD("create video converter: %s", video_csc);
3391 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3394 *bucket = element_bucket;
3396 return MM_ERROR_NONE;
3398 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3399 g_list_free(element_bucket);
3403 return MM_ERROR_PLAYER_INTERNAL;
3407 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3409 gchar *factory_name = NULL;
3411 switch (surface_type) {
3412 case MM_DISPLAY_SURFACE_OVERLAY:
3413 if (strlen(player->ini.videosink_element_overlay) > 0)
3414 factory_name = player->ini.videosink_element_overlay;
3416 case MM_DISPLAY_SURFACE_REMOTE:
3417 case MM_DISPLAY_SURFACE_NULL:
3418 if (strlen(player->ini.videosink_element_fake) > 0)
3419 factory_name = player->ini.videosink_element_fake;
3422 LOGE("unidentified surface type");
3426 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3427 return factory_name;
3431 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3433 gchar *factory_name = NULL;
3434 mmplayer_gst_element_t *videobin = NULL;
3439 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3441 videobin = player->pipeline->videobin;
3442 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3444 attrs = MMPLAYER_GET_ATTRS(player);
3446 LOGE("cannot get content attribute");
3447 return MM_ERROR_PLAYER_INTERNAL;
3450 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3451 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3452 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3454 /* support shard memory with S/W codec on HawkP */
3455 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3456 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3457 "use-tbm", use_tbm, NULL);
3461 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3462 return MM_ERROR_PLAYER_INTERNAL;
3464 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3465 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3468 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3470 LOGD("disable last-sample");
3471 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3474 if (player->set_mode.video_export) {
3476 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3477 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3478 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3480 _mmplayer_add_signal_connection(player,
3481 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3482 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3484 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3487 _mmplayer_add_signal_connection(player,
3488 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3489 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3491 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3495 if (videobin[MMPLAYER_V_SINK].gst) {
3496 GstPad *sink_pad = NULL;
3497 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3499 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3500 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3501 gst_object_unref(GST_OBJECT(sink_pad));
3503 LOGE("failed to get sink pad from videosink");
3507 return MM_ERROR_NONE;
3512 * - video overlay surface(arm/x86) : tizenwlsink
3515 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3518 GList *element_bucket = NULL;
3519 mmplayer_gst_element_t *first_element = NULL;
3520 mmplayer_gst_element_t *videobin = NULL;
3521 gchar *videosink_factory_name = NULL;
3524 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3527 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3529 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3531 player->pipeline->videobin = videobin;
3534 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3535 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3536 if (!videobin[MMPLAYER_V_BIN].gst) {
3537 LOGE("failed to create videobin");
3541 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3544 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3545 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3547 /* additional setting for sink plug-in */
3548 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3549 LOGE("failed to set video property");
3553 /* store it as it's sink element */
3554 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3556 /* adding created elements to bin */
3557 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3558 LOGE("failed to add elements");
3562 /* Linking elements in the bucket by added order */
3563 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3564 LOGE("failed to link elements");
3568 /* get first element's sinkpad for creating ghostpad */
3569 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3570 if (!first_element) {
3571 LOGE("failed to get first element from bucket");
3575 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3577 LOGE("failed to get pad from first element");
3581 /* create ghostpad */
3582 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3583 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3584 LOGE("failed to add ghostpad to videobin");
3587 gst_object_unref(pad);
3589 /* done. free allocated variables */
3590 g_list_free(element_bucket);
3594 return MM_ERROR_NONE;
3597 LOGE("ERROR : releasing videobin");
3598 g_list_free(element_bucket);
3601 gst_object_unref(GST_OBJECT(pad));
3603 /* release videobin with it's childs */
3604 if (videobin[MMPLAYER_V_BIN].gst)
3605 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3607 MMPLAYER_FREEIF(videobin);
3608 player->pipeline->videobin = NULL;
3610 return MM_ERROR_PLAYER_INTERNAL;
3614 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3616 GList *element_bucket = NULL;
3617 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3619 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3620 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3621 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3622 "signal-handoffs", FALSE,
3625 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3626 _mmplayer_add_signal_connection(player,
3627 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3628 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3630 G_CALLBACK(__mmplayer_update_subtitle),
3633 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3634 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3636 if (!player->play_subtitle) {
3637 LOGD("add textbin sink as sink element of whole pipeline.");
3638 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3641 /* adding created elements to bin */
3642 LOGD("adding created elements to bin");
3643 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3644 LOGE("failed to add elements");
3648 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3649 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3650 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3652 /* linking elements in the bucket by added order. */
3653 LOGD("Linking elements in the bucket by added order.");
3654 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3655 LOGE("failed to link elements");
3659 /* done. free allocated variables */
3660 g_list_free(element_bucket);
3662 if (textbin[MMPLAYER_T_QUEUE].gst) {
3664 GstPad *ghostpad = NULL;
3666 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3668 LOGE("failed to get sink pad of text queue");
3672 ghostpad = gst_ghost_pad_new("text_sink", pad);
3673 gst_object_unref(pad);
3676 LOGE("failed to create ghostpad of textbin");
3680 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3681 LOGE("failed to add ghostpad to textbin");
3682 gst_object_unref(ghostpad);
3687 return MM_ERROR_NONE;
3690 g_list_free(element_bucket);
3692 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3693 LOGE("remove textbin sink from sink list");
3694 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3697 /* release element at __mmplayer_gst_create_text_sink_bin */
3698 return MM_ERROR_PLAYER_INTERNAL;
3702 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3704 mmplayer_gst_element_t *textbin = NULL;
3705 GList *element_bucket = NULL;
3706 int surface_type = 0;
3711 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3714 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3716 LOGE("failed to allocate memory for textbin");
3717 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3721 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3722 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3723 if (!textbin[MMPLAYER_T_BIN].gst) {
3724 LOGE("failed to create textbin");
3729 player->pipeline->textbin = textbin;
3732 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3733 LOGD("surface type for subtitle : %d", surface_type);
3734 switch (surface_type) {
3735 case MM_DISPLAY_SURFACE_OVERLAY:
3736 case MM_DISPLAY_SURFACE_NULL:
3737 case MM_DISPLAY_SURFACE_REMOTE:
3738 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3739 LOGE("failed to make plain text elements");
3750 return MM_ERROR_NONE;
3754 LOGD("ERROR : releasing textbin");
3756 g_list_free(element_bucket);
3758 /* release signal */
3759 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3761 /* release element which are not added to bin */
3762 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3763 /* NOTE : skip bin */
3764 if (textbin[i].gst) {
3765 GstObject *parent = NULL;
3766 parent = gst_element_get_parent(textbin[i].gst);
3769 gst_object_unref(GST_OBJECT(textbin[i].gst));
3770 textbin[i].gst = NULL;
3772 gst_object_unref(GST_OBJECT(parent));
3777 /* release textbin with it's childs */
3778 if (textbin[MMPLAYER_T_BIN].gst)
3779 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3781 MMPLAYER_FREEIF(player->pipeline->textbin);
3782 player->pipeline->textbin = NULL;
3785 return MM_ERROR_PLAYER_INTERNAL;
3789 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3791 mmplayer_gst_element_t *mainbin = NULL;
3792 mmplayer_gst_element_t *textbin = NULL;
3793 MMHandleType attrs = 0;
3794 GstElement *subsrc = NULL;
3795 GstElement *subparse = NULL;
3796 gchar *subtitle_uri = NULL;
3797 const gchar *charset = NULL;
3803 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3805 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3807 mainbin = player->pipeline->mainbin;
3809 attrs = MMPLAYER_GET_ATTRS(player);
3811 LOGE("cannot get content attribute");
3812 return MM_ERROR_PLAYER_INTERNAL;
3815 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3816 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3817 LOGE("subtitle uri is not proper filepath.");
3818 return MM_ERROR_PLAYER_INVALID_URI;
3821 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3822 LOGE("failed to get storage info of subtitle path");
3823 return MM_ERROR_PLAYER_INVALID_URI;
3826 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3828 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3829 player->subtitle_language_list = NULL;
3830 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3832 /* create the subtitle source */
3833 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3835 LOGE("failed to create filesrc element");
3838 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3840 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3841 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3843 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3844 LOGW("failed to add queue");
3845 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3846 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3847 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3852 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3854 LOGE("failed to create subparse element");
3858 charset = _mmplayer_get_charset(subtitle_uri);
3860 LOGD("detected charset is %s", charset);
3861 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3864 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3865 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3867 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3868 LOGW("failed to add subparse");
3869 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3870 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3871 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3875 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3876 LOGW("failed to link subsrc and subparse");
3880 player->play_subtitle = TRUE;
3881 player->adjust_subtitle_pos = 0;
3883 LOGD("play subtitle using subtitle file");
3885 if (player->pipeline->textbin == NULL) {
3886 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3887 LOGE("failed to create text sink bin. continuing without text");
3891 textbin = player->pipeline->textbin;
3893 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3894 LOGW("failed to add textbin");
3896 /* release signal */
3897 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3899 /* release textbin with it's childs */
3900 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3901 MMPLAYER_FREEIF(player->pipeline->textbin);
3902 player->pipeline->textbin = textbin = NULL;
3906 LOGD("link text input selector and textbin ghost pad");
3908 player->textsink_linked = 1;
3909 player->external_text_idx = 0;
3910 LOGI("textsink is linked");
3912 textbin = player->pipeline->textbin;
3913 LOGD("text bin has been created. reuse it.");
3914 player->external_text_idx = 1;
3917 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3918 LOGW("failed to link subparse and textbin");
3922 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3924 LOGE("failed to get sink pad from textsink to probe data");
3928 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3929 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3931 gst_object_unref(pad);
3934 /* create dot. for debugging */
3935 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3938 return MM_ERROR_NONE;
3941 /* release text pipeline resource */
3942 player->textsink_linked = 0;
3944 /* release signal */
3945 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3947 if (player->pipeline->textbin) {
3948 LOGE("remove textbin");
3950 /* release textbin with it's childs */
3951 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3952 MMPLAYER_FREEIF(player->pipeline->textbin);
3953 player->pipeline->textbin = NULL;
3957 /* release subtitle elem */
3958 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3959 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3961 return MM_ERROR_PLAYER_INTERNAL;
3965 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3967 mmplayer_t *player = (mmplayer_t *)data;
3968 MMMessageParamType msg = {0, };
3969 GstClockTime duration = 0;
3970 gpointer text = NULL;
3971 guint text_size = 0;
3972 gboolean ret = TRUE;
3973 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3977 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3978 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3980 if (player->is_subtitle_force_drop) {
3981 LOGW("subtitle is dropped forcedly.");
3985 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3986 text = mapinfo.data;
3987 text_size = mapinfo.size;
3989 if (player->set_mode.subtitle_off) {
3990 LOGD("subtitle is OFF.");
3994 if (!text || (text_size == 0)) {
3995 LOGD("There is no subtitle to be displayed.");
3999 msg.data = (void *)text;
4001 duration = GST_BUFFER_DURATION(buffer);
4003 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4004 if (player->duration > GST_BUFFER_PTS(buffer))
4005 duration = player->duration - GST_BUFFER_PTS(buffer);
4008 LOGI("subtitle duration is invalid, subtitle duration change "
4009 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4011 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4013 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4015 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4016 gst_buffer_unmap(buffer, &mapinfo);
4023 static GstPadProbeReturn
4024 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4026 mmplayer_t *player = (mmplayer_t *)u_data;
4027 GstClockTime cur_timestamp = 0;
4028 gint64 adjusted_timestamp = 0;
4029 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4031 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4033 if (player->set_mode.subtitle_off) {
4034 LOGD("subtitle is OFF.");
4038 if (player->adjust_subtitle_pos == 0) {
4039 LOGD("nothing to do");
4043 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4044 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4046 if (adjusted_timestamp < 0) {
4047 LOGD("adjusted_timestamp under zero");
4052 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4053 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4054 GST_TIME_ARGS(cur_timestamp),
4055 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4057 return GST_PAD_PROBE_OK;
4061 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4065 /* check player and subtitlebin are created */
4066 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4067 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4069 if (position == 0) {
4070 LOGD("nothing to do");
4072 return MM_ERROR_NONE;
4075 /* check current postion */
4076 player->adjust_subtitle_pos = position;
4078 LOGD("save adjust_subtitle_pos in player");
4082 return MM_ERROR_NONE;
4086 * This function is to create audio or video pipeline for playing.
4088 * @param player [in] handle of player
4090 * @return This function returns zero on success.
4095 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4097 int ret = MM_ERROR_NONE;
4098 mmplayer_gst_element_t *mainbin = NULL;
4099 MMHandleType attrs = 0;
4102 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4104 /* get profile attribute */
4105 attrs = MMPLAYER_GET_ATTRS(player);
4107 LOGE("failed to get content attribute");
4111 /* create pipeline handles */
4112 if (player->pipeline) {
4113 LOGE("pipeline should be released before create new one");
4117 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4118 if (player->pipeline == NULL)
4121 /* create mainbin */
4122 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4123 if (mainbin == NULL)
4126 /* create pipeline */
4127 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4128 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4129 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4130 LOGE("failed to create pipeline");
4135 player->pipeline->mainbin = mainbin;
4137 /* create the source and decoder elements */
4138 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4139 ret = _mmplayer_gst_build_es_pipeline(player);
4141 ret = _mmplayer_gst_build_pipeline(player);
4143 if (ret != MM_ERROR_NONE) {
4144 LOGE("failed to create some elements");
4148 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4149 if (__mmplayer_check_subtitle(player)
4150 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4151 LOGE("failed to create text pipeline");
4154 ret = _mmplayer_gst_add_bus_watch(player);
4155 if (ret != MM_ERROR_NONE) {
4156 LOGE("failed to add bus watch");
4161 return MM_ERROR_NONE;
4164 __mmplayer_gst_destroy_pipeline(player);
4165 return MM_ERROR_PLAYER_INTERNAL;
4169 __mmplayer_reset_gapless_state(mmplayer_t *player)
4172 MMPLAYER_RETURN_IF_FAIL(player
4174 && player->pipeline->audiobin
4175 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4177 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4184 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4187 int ret = MM_ERROR_NONE;
4191 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4193 /* cleanup stuffs */
4194 MMPLAYER_FREEIF(player->type);
4195 player->no_more_pad = FALSE;
4196 player->num_dynamic_pad = 0;
4197 player->demux_pad_index = 0;
4199 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4200 player->subtitle_language_list = NULL;
4201 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4203 __mmplayer_reset_gapless_state(player);
4205 if (player->streamer) {
4206 _mm_player_streaming_initialize(player->streamer, FALSE);
4207 _mm_player_streaming_destroy(player->streamer);
4208 player->streamer = NULL;
4211 /* cleanup unlinked mime type */
4212 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4213 MMPLAYER_FREEIF(player->unlinked_video_mime);
4214 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4216 /* cleanup running stuffs */
4217 _mmplayer_cancel_eos_timer(player);
4219 /* cleanup gst stuffs */
4220 if (player->pipeline) {
4221 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4222 GstTagList *tag_list = player->pipeline->tag_list;
4224 /* first we need to disconnect all signal hander */
4225 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4228 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4229 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4230 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4231 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4232 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4233 gst_object_unref(bus);
4235 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4236 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4237 if (ret != MM_ERROR_NONE) {
4238 LOGE("fail to change state to NULL");
4239 return MM_ERROR_PLAYER_INTERNAL;
4242 LOGW("succeeded in changing state to NULL");
4244 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4247 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4248 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4250 /* free avsysaudiosink
4251 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4252 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4254 MMPLAYER_FREEIF(audiobin);
4255 MMPLAYER_FREEIF(videobin);
4256 MMPLAYER_FREEIF(textbin);
4257 MMPLAYER_FREEIF(mainbin);
4261 gst_tag_list_unref(tag_list);
4263 MMPLAYER_FREEIF(player->pipeline);
4265 MMPLAYER_FREEIF(player->album_art);
4267 if (player->v_stream_caps) {
4268 gst_caps_unref(player->v_stream_caps);
4269 player->v_stream_caps = NULL;
4272 if (player->a_stream_caps) {
4273 gst_caps_unref(player->a_stream_caps);
4274 player->a_stream_caps = NULL;
4277 if (player->s_stream_caps) {
4278 gst_caps_unref(player->s_stream_caps);
4279 player->s_stream_caps = NULL;
4281 _mmplayer_track_destroy(player);
4283 if (player->sink_elements)
4284 g_list_free(player->sink_elements);
4285 player->sink_elements = NULL;
4287 if (player->bufmgr) {
4288 tbm_bufmgr_deinit(player->bufmgr);
4289 player->bufmgr = NULL;
4292 LOGW("finished destroy pipeline");
4300 __mmplayer_gst_realize(mmplayer_t *player)
4303 int ret = MM_ERROR_NONE;
4307 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4309 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4311 ret = __mmplayer_gst_create_pipeline(player);
4313 LOGE("failed to create pipeline");
4317 /* set pipeline state to READY */
4318 /* NOTE : state change to READY must be performed sync. */
4319 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4320 ret = _mmplayer_gst_set_state(player,
4321 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4323 if (ret != MM_ERROR_NONE) {
4324 /* return error if failed to set state */
4325 LOGE("failed to set READY state");
4329 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4331 /* create dot before error-return. for debugging */
4332 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4340 __mmplayer_gst_unrealize(mmplayer_t *player)
4342 int ret = MM_ERROR_NONE;
4346 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4348 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4349 MMPLAYER_PRINT_STATE(player);
4351 /* release miscellaneous information */
4352 __mmplayer_release_misc(player);
4354 /* destroy pipeline */
4355 ret = __mmplayer_gst_destroy_pipeline(player);
4356 if (ret != MM_ERROR_NONE) {
4357 LOGE("failed to destory pipeline");
4361 /* release miscellaneous information.
4362 these info needs to be released after pipeline is destroyed. */
4363 __mmplayer_release_misc_post(player);
4365 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4373 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4378 LOGW("set_message_callback is called with invalid player handle");
4379 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4382 player->msg_cb = callback;
4383 player->msg_cb_param = user_param;
4385 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4389 return MM_ERROR_NONE;
4393 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4395 int ret = MM_ERROR_NONE;
4400 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4401 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4402 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4404 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4406 if (strstr(uri, "es_buff://")) {
4407 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4408 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4409 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4410 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4412 tmp = g_ascii_strdown(uri, strlen(uri));
4413 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4414 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4416 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4418 } else if (strstr(uri, "mms://")) {
4419 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4420 } else if ((path = strstr(uri, "mem://"))) {
4421 ret = __mmplayer_set_mem_uri(data, path, param);
4423 ret = __mmplayer_set_file_uri(data, uri);
4426 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4427 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4428 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4429 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4431 /* dump parse result */
4432 SECURE_LOGW("incoming uri : %s", uri);
4433 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4434 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4442 __mmplayer_can_do_interrupt(mmplayer_t *player)
4444 if (!player || !player->pipeline || !player->attrs) {
4445 LOGW("not initialized");
4449 if (player->audio_decoded_cb) {
4450 LOGW("not support in pcm extraction mode");
4454 /* check if seeking */
4455 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4456 MMMessageParamType msg_param;
4457 memset(&msg_param, 0, sizeof(MMMessageParamType));
4458 msg_param.code = MM_ERROR_PLAYER_SEEK;
4459 player->seek_state = MMPLAYER_SEEK_NONE;
4460 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4464 /* check other thread */
4465 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4466 LOGW("locked already, cmd state : %d", player->cmd);
4468 /* check application command */
4469 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4470 LOGW("playing.. should wait cmd lock then, will be interrupted");
4472 /* lock will be released at mrp_resource_release_cb() */
4473 MMPLAYER_CMD_LOCK(player);
4476 LOGW("nothing to do");
4479 LOGW("can interrupt immediately");
4483 FAILED: /* with CMD UNLOCKED */
4486 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4491 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4494 mmplayer_t *player = NULL;
4495 MMMessageParamType msg = {0, };
4497 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4502 LOGE("user_data is null");
4505 player = (mmplayer_t *)user_data;
4507 if (!__mmplayer_can_do_interrupt(player)) {
4508 LOGW("no need to interrupt, so leave");
4509 /* FIXME: there is no way to avoid releasing resource. */
4513 player->interrupted_by_resource = TRUE;
4515 /* get last play position */
4516 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4517 msg.union_type = MM_MSG_UNION_TIME;
4518 msg.time.elapsed = pos;
4519 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4521 LOGW("failed to get play position.");
4524 LOGD("video resource conflict so, resource will be freed by unrealizing");
4525 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4526 LOGE("failed to unrealize");
4528 /* lock is called in __mmplayer_can_do_interrupt() */
4529 MMPLAYER_CMD_UNLOCK(player);
4531 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4532 player->hw_resource[res_idx] = NULL;
4536 return TRUE; /* release all the resources */
4540 __mmplayer_initialize_video_roi(mmplayer_t *player)
4542 player->video_roi.scale_x = 0.0;
4543 player->video_roi.scale_y = 0.0;
4544 player->video_roi.scale_width = 1.0;
4545 player->video_roi.scale_height = 1.0;
4549 _mmplayer_create_player(MMHandleType handle)
4551 int ret = MM_ERROR_PLAYER_INTERNAL;
4552 bool enabled = false;
4554 mmplayer_t *player = MM_PLAYER_CAST(handle);
4558 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4560 /* initialize player state */
4561 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4562 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4563 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4564 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4566 /* check current state */
4567 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4569 /* construct attributes */
4570 player->attrs = _mmplayer_construct_attribute(handle);
4572 if (!player->attrs) {
4573 LOGE("Failed to construct attributes");
4577 /* initialize gstreamer with configured parameter */
4578 if (!__mmplayer_init_gstreamer(player)) {
4579 LOGE("Initializing gstreamer failed");
4580 _mmplayer_deconstruct_attribute(handle);
4584 /* create lock. note that g_tread_init() has already called in gst_init() */
4585 g_mutex_init(&player->fsink_lock);
4587 /* create update tag lock */
4588 g_mutex_init(&player->update_tag_lock);
4590 /* create gapless play mutex */
4591 g_mutex_init(&player->gapless_play_thread_mutex);
4593 /* create gapless play cond */
4594 g_cond_init(&player->gapless_play_thread_cond);
4596 /* create gapless play thread */
4597 player->gapless_play_thread =
4598 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4599 if (!player->gapless_play_thread) {
4600 LOGE("failed to create gapless play thread");
4601 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4602 g_mutex_clear(&player->gapless_play_thread_mutex);
4603 g_cond_clear(&player->gapless_play_thread_cond);
4607 player->bus_msg_q = g_queue_new();
4608 if (!player->bus_msg_q) {
4609 LOGE("failed to create queue for bus_msg");
4610 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4614 ret = _mmplayer_initialize_video_capture(player);
4615 if (ret != MM_ERROR_NONE) {
4616 LOGE("failed to initialize video capture");
4620 /* initialize resource manager */
4621 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4622 __resource_release_cb, player, &player->resource_manager)
4623 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4624 LOGE("failed to initialize resource manager");
4625 ret = MM_ERROR_PLAYER_INTERNAL;
4629 /* create video bo lock and cond */
4630 g_mutex_init(&player->video_bo_mutex);
4631 g_cond_init(&player->video_bo_cond);
4633 /* create subtitle info lock and cond */
4634 g_mutex_init(&player->subtitle_info_mutex);
4635 g_cond_init(&player->subtitle_info_cond);
4637 player->streaming_type = STREAMING_SERVICE_NONE;
4639 /* give default value of audio effect setting */
4640 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4641 player->sound.rg_enable = false;
4642 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4644 player->play_subtitle = FALSE;
4645 player->has_closed_caption = FALSE;
4646 player->pending_resume = FALSE;
4647 if (player->ini.dump_element_keyword[0][0] == '\0')
4648 player->ini.set_dump_element_flag = FALSE;
4650 player->ini.set_dump_element_flag = TRUE;
4652 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4653 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4654 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4656 /* Set video360 settings to their defaults for just-created player.
4659 player->is_360_feature_enabled = FALSE;
4660 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4661 LOGI("spherical feature info: %d", enabled);
4663 player->is_360_feature_enabled = TRUE;
4665 LOGE("failed to get spherical feature info");
4668 player->is_content_spherical = FALSE;
4669 player->is_video360_enabled = TRUE;
4670 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4671 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4672 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4673 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4674 player->video360_zoom = 1.0f;
4675 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4676 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4678 __mmplayer_initialize_video_roi(player);
4680 /* set player state to null */
4681 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4682 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4686 return MM_ERROR_NONE;
4690 g_mutex_clear(&player->fsink_lock);
4691 /* free update tag lock */
4692 g_mutex_clear(&player->update_tag_lock);
4693 g_queue_free(player->bus_msg_q);
4694 player->bus_msg_q = NULL;
4695 /* free gapless play thread */
4696 if (player->gapless_play_thread) {
4697 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4698 player->gapless_play_thread_exit = TRUE;
4699 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4700 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4702 g_thread_join(player->gapless_play_thread);
4703 player->gapless_play_thread = NULL;
4705 g_mutex_clear(&player->gapless_play_thread_mutex);
4706 g_cond_clear(&player->gapless_play_thread_cond);
4709 /* release attributes */
4710 _mmplayer_deconstruct_attribute(handle);
4718 __mmplayer_init_gstreamer(mmplayer_t *player)
4720 static gboolean initialized = FALSE;
4721 static const int max_argc = 50;
4723 gchar **argv = NULL;
4724 gchar **argv2 = NULL;
4730 LOGD("gstreamer already initialized.");
4735 argc = malloc(sizeof(int));
4736 argv = malloc(sizeof(gchar *) * max_argc);
4737 argv2 = malloc(sizeof(gchar *) * max_argc);
4739 if (!argc || !argv || !argv2)
4742 memset(argv, 0, sizeof(gchar *) * max_argc);
4743 memset(argv2, 0, sizeof(gchar *) * max_argc);
4747 argv[0] = g_strdup("mmplayer");
4750 for (i = 0; i < 5; i++) {
4751 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4752 if (strlen(player->ini.gst_param[i]) > 0) {
4753 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4758 /* we would not do fork for scanning plugins */
4759 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4762 /* check disable registry scan */
4763 if (player->ini.skip_rescan) {
4764 argv[*argc] = g_strdup("--gst-disable-registry-update");
4768 /* check disable segtrap */
4769 if (player->ini.disable_segtrap) {
4770 argv[*argc] = g_strdup("--gst-disable-segtrap");
4774 LOGD("initializing gstreamer with following parameter");
4775 LOGD("argc : %d", *argc);
4778 for (i = 0; i < arg_count; i++) {
4780 LOGD("argv[%d] : %s", i, argv2[i]);
4783 /* initializing gstreamer */
4784 if (!gst_init_check(argc, &argv, &err)) {
4785 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4792 for (i = 0; i < arg_count; i++) {
4794 LOGD("release - argv[%d] : %s", i, argv2[i]);
4796 MMPLAYER_FREEIF(argv2[i]);
4799 MMPLAYER_FREEIF(argv);
4800 MMPLAYER_FREEIF(argv2);
4801 MMPLAYER_FREEIF(argc);
4811 for (i = 0; i < arg_count; i++) {
4812 LOGD("free[%d] : %s", i, argv2[i]);
4813 MMPLAYER_FREEIF(argv2[i]);
4816 MMPLAYER_FREEIF(argv);
4817 MMPLAYER_FREEIF(argv2);
4818 MMPLAYER_FREEIF(argc);
4824 __mmplayer_check_async_state_transition(mmplayer_t *player)
4826 GstState element_state = GST_STATE_VOID_PENDING;
4827 GstState element_pending_state = GST_STATE_VOID_PENDING;
4828 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4829 GstElement *element = NULL;
4830 gboolean async = FALSE;
4832 /* check player handle */
4833 MMPLAYER_RETURN_IF_FAIL(player &&
4835 player->pipeline->mainbin &&
4836 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4839 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4841 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4842 LOGD("don't need to check the pipeline state");
4846 MMPLAYER_PRINT_STATE(player);
4848 /* wait for state transition */
4849 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4850 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4852 if (ret == GST_STATE_CHANGE_FAILURE) {
4853 LOGE(" [%s] state : %s pending : %s",
4854 GST_ELEMENT_NAME(element),
4855 gst_element_state_get_name(element_state),
4856 gst_element_state_get_name(element_pending_state));
4858 /* dump state of all element */
4859 _mmplayer_dump_pipeline_state(player);
4864 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4869 _mmplayer_destroy(MMHandleType handle)
4871 mmplayer_t *player = MM_PLAYER_CAST(handle);
4875 /* check player handle */
4876 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4878 /* destroy can called at anytime */
4879 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4881 /* check async state transition */
4882 __mmplayer_check_async_state_transition(player);
4884 /* release gapless play thread */
4885 if (player->gapless_play_thread) {
4886 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4887 player->gapless_play_thread_exit = TRUE;
4888 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4889 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4891 LOGD("waitting for gapless play thread exit");
4892 g_thread_join(player->gapless_play_thread);
4893 g_mutex_clear(&player->gapless_play_thread_mutex);
4894 g_cond_clear(&player->gapless_play_thread_cond);
4895 LOGD("gapless play thread released");
4898 _mmplayer_release_video_capture(player);
4900 /* de-initialize resource manager */
4901 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4902 player->resource_manager))
4903 LOGE("failed to deinitialize resource manager");
4905 /* release pipeline */
4906 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4907 LOGE("failed to destory pipeline");
4908 return MM_ERROR_PLAYER_INTERNAL;
4911 g_queue_free(player->bus_msg_q);
4913 /* release subtitle info lock and cond */
4914 g_mutex_clear(&player->subtitle_info_mutex);
4915 g_cond_clear(&player->subtitle_info_cond);
4917 __mmplayer_release_dump_list(player->dump_list);
4919 /* release miscellaneous information */
4920 __mmplayer_release_misc(player);
4922 /* release miscellaneous information.
4923 these info needs to be released after pipeline is destroyed. */
4924 __mmplayer_release_misc_post(player);
4926 /* release attributes */
4927 _mmplayer_deconstruct_attribute(handle);
4930 g_mutex_clear(&player->fsink_lock);
4933 g_mutex_clear(&player->update_tag_lock);
4935 /* release video bo lock and cond */
4936 g_mutex_clear(&player->video_bo_mutex);
4937 g_cond_clear(&player->video_bo_cond);
4941 return MM_ERROR_NONE;
4945 _mmplayer_realize(MMHandleType hplayer)
4947 mmplayer_t *player = (mmplayer_t *)hplayer;
4950 MMHandleType attrs = 0;
4951 int ret = MM_ERROR_NONE;
4955 /* check player handle */
4956 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4958 /* check current state */
4959 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4961 attrs = MMPLAYER_GET_ATTRS(player);
4963 LOGE("fail to get attributes.");
4964 return MM_ERROR_PLAYER_INTERNAL;
4966 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4967 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4969 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4970 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
4972 if (ret != MM_ERROR_NONE) {
4973 LOGE("failed to parse profile");
4978 if (uri && (strstr(uri, "es_buff://"))) {
4979 if (strstr(uri, "es_buff://push_mode"))
4980 player->es_player_push_mode = TRUE;
4982 player->es_player_push_mode = FALSE;
4985 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4986 LOGW("mms protocol is not supported format.");
4987 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4990 if (MMPLAYER_IS_STREAMING(player))
4991 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4993 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4995 player->smooth_streaming = FALSE;
4996 player->videodec_linked = 0;
4997 player->audiodec_linked = 0;
4998 player->textsink_linked = 0;
4999 player->is_external_subtitle_present = FALSE;
5000 player->is_external_subtitle_added_now = FALSE;
5001 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5002 player->video360_metadata.is_spherical = -1;
5003 player->is_openal_plugin_used = FALSE;
5004 player->demux_pad_index = 0;
5005 player->subtitle_language_list = NULL;
5006 player->is_subtitle_force_drop = FALSE;
5008 _mmplayer_track_initialize(player);
5009 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5011 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5012 gint prebuffer_ms = 0, rebuffer_ms = 0;
5014 player->streamer = _mm_player_streaming_create();
5015 _mm_player_streaming_initialize(player->streamer, TRUE);
5017 mm_attrs_multiple_get(player->attrs, NULL,
5018 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5019 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5021 if (prebuffer_ms > 0) {
5022 prebuffer_ms = MAX(prebuffer_ms, 1000);
5023 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5026 if (rebuffer_ms > 0) {
5027 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5028 rebuffer_ms = MAX(rebuffer_ms, 1000);
5029 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5032 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5033 player->streamer->buffering_req.rebuffer_time);
5036 /* realize pipeline */
5037 ret = __mmplayer_gst_realize(player);
5038 if (ret != MM_ERROR_NONE)
5039 LOGE("fail to realize the player.");
5041 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5049 _mmplayer_unrealize(MMHandleType hplayer)
5051 mmplayer_t *player = (mmplayer_t *)hplayer;
5052 int ret = MM_ERROR_NONE;
5056 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5058 MMPLAYER_CMD_UNLOCK(player);
5059 /* destroy the gst bus msg thread which is created during realize.
5060 this funct have to be called before getting cmd lock. */
5061 _mmplayer_bus_msg_thread_destroy(player);
5062 MMPLAYER_CMD_LOCK(player);
5064 /* check current state */
5065 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5067 /* check async state transition */
5068 __mmplayer_check_async_state_transition(player);
5070 /* unrealize pipeline */
5071 ret = __mmplayer_gst_unrealize(player);
5073 if (!player->interrupted_by_resource) {
5074 int rm_ret = MM_ERROR_NONE;
5075 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5077 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5078 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5079 if (rm_ret != MM_ERROR_NONE)
5080 LOGE("failed to release [%d] resources", res_idx);
5089 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5091 mmplayer_t *player = (mmplayer_t *)hplayer;
5093 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5095 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5099 _mmplayer_get_state(MMHandleType hplayer, int *state)
5101 mmplayer_t *player = (mmplayer_t *)hplayer;
5103 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5105 *state = MMPLAYER_CURRENT_STATE(player);
5107 return MM_ERROR_NONE;
5111 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5113 GstElement *vol_element = NULL;
5114 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5117 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5118 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5120 /* check pipeline handle */
5121 if (!player->pipeline || !player->pipeline->audiobin) {
5122 LOGD("'%s' will be applied when audiobin is created", prop_name);
5124 /* NOTE : stored value will be used in create_audiobin
5125 * returning MM_ERROR_NONE here makes application to able to
5126 * set audio volume or mute at anytime.
5128 return MM_ERROR_NONE;
5131 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5132 volume_elem_id = MMPLAYER_A_SINK;
5134 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5136 LOGE("failed to get vol element %d", volume_elem_id);
5137 return MM_ERROR_PLAYER_INTERNAL;
5140 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5142 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5143 LOGE("there is no '%s' property", prop_name);
5144 return MM_ERROR_PLAYER_INTERNAL;
5147 if (!strcmp(prop_name, "volume")) {
5148 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5149 } else if (!strcmp(prop_name, "mute")) {
5150 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5152 LOGE("invalid property %s", prop_name);
5153 return MM_ERROR_PLAYER_INTERNAL;
5156 return MM_ERROR_NONE;
5160 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5162 int ret = MM_ERROR_NONE;
5163 mmplayer_t *player = (mmplayer_t *)hplayer;
5166 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5168 LOGD("volume = %f", volume);
5170 /* invalid factor range or not */
5171 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5172 LOGE("Invalid volume value");
5173 return MM_ERROR_INVALID_ARGUMENT;
5176 player->sound.volume = volume;
5178 ret = __mmplayer_gst_set_volume_property(player, "volume");
5185 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5187 mmplayer_t *player = (mmplayer_t *)hplayer;
5191 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5192 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5194 *volume = player->sound.volume;
5196 LOGD("current vol = %f", *volume);
5199 return MM_ERROR_NONE;
5203 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5205 int ret = MM_ERROR_NONE;
5206 mmplayer_t *player = (mmplayer_t *)hplayer;
5209 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5211 LOGD("mute = %d", mute);
5213 player->sound.mute = mute;
5215 ret = __mmplayer_gst_set_volume_property(player, "mute");
5222 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5224 mmplayer_t *player = (mmplayer_t *)hplayer;
5228 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5229 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5231 *mute = player->sound.mute;
5233 LOGD("current mute = %d", *mute);
5237 return MM_ERROR_NONE;
5241 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5243 mmplayer_t *player = (mmplayer_t *)hplayer;
5247 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5249 player->audio_stream_changed_cb = callback;
5250 player->audio_stream_changed_cb_user_param = user_param;
5251 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5255 return MM_ERROR_NONE;
5259 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5261 mmplayer_t *player = (mmplayer_t *)hplayer;
5265 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5267 player->audio_decoded_cb = callback;
5268 player->audio_decoded_cb_user_param = user_param;
5269 player->audio_extract_opt = opt;
5270 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5274 return MM_ERROR_NONE;
5278 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5280 mmplayer_t *player = (mmplayer_t *)hplayer;
5284 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5286 if (callback && !player->bufmgr)
5287 player->bufmgr = tbm_bufmgr_init(-1);
5289 player->set_mode.video_export = (callback) ? true : false;
5290 player->video_decoded_cb = callback;
5291 player->video_decoded_cb_user_param = user_param;
5293 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5297 return MM_ERROR_NONE;
5301 _mmplayer_start(MMHandleType hplayer)
5303 mmplayer_t *player = (mmplayer_t *)hplayer;
5304 gint ret = MM_ERROR_NONE;
5308 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5310 /* check current state */
5311 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5313 /* start pipeline */
5314 ret = _mmplayer_gst_start(player);
5315 if (ret != MM_ERROR_NONE)
5316 LOGE("failed to start player.");
5318 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5319 LOGD("force playing start even during buffering");
5320 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5328 /* NOTE: post "not supported codec message" to application
5329 * when one codec is not found during AUTOPLUGGING in MSL.
5330 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5331 * And, if any codec is not found, don't send message here.
5332 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5335 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5337 MMMessageParamType msg_param;
5338 memset(&msg_param, 0, sizeof(MMMessageParamType));
5339 gboolean post_msg_direct = FALSE;
5343 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5345 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5346 player->not_supported_codec, player->can_support_codec);
5348 if (player->not_found_demuxer) {
5349 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5350 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5352 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5353 MMPLAYER_FREEIF(msg_param.data);
5355 return MM_ERROR_NONE;
5358 if (player->not_supported_codec) {
5359 if (player->can_support_codec) {
5360 // There is one codec to play
5361 post_msg_direct = TRUE;
5363 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5364 post_msg_direct = TRUE;
5367 if (post_msg_direct) {
5368 MMMessageParamType msg_param;
5369 memset(&msg_param, 0, sizeof(MMMessageParamType));
5371 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5372 LOGW("not found AUDIO codec, posting error code to application.");
5374 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5375 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5376 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5377 LOGW("not found VIDEO codec, posting error code to application.");
5379 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5380 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5383 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5385 MMPLAYER_FREEIF(msg_param.data);
5387 return MM_ERROR_NONE;
5389 // no any supported codec case
5390 LOGW("not found any codec, posting error code to application.");
5392 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5393 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5394 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5396 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5397 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5400 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5402 MMPLAYER_FREEIF(msg_param.data);
5408 return MM_ERROR_NONE;
5412 __mmplayer_check_pipeline(mmplayer_t *player)
5414 GstState element_state = GST_STATE_VOID_PENDING;
5415 GstState element_pending_state = GST_STATE_VOID_PENDING;
5417 int ret = MM_ERROR_NONE;
5419 if (!player->gapless.reconfigure)
5422 LOGW("pipeline is under construction.");
5424 MMPLAYER_PLAYBACK_LOCK(player);
5425 MMPLAYER_PLAYBACK_UNLOCK(player);
5427 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5429 /* wait for state transition */
5430 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5431 if (ret == GST_STATE_CHANGE_FAILURE)
5432 LOGE("failed to change pipeline state within %d sec", timeout);
5435 /* NOTE : it should be able to call 'stop' anytime*/
5437 _mmplayer_stop(MMHandleType hplayer)
5439 mmplayer_t *player = (mmplayer_t *)hplayer;
5440 int ret = MM_ERROR_NONE;
5444 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5446 /* check current state */
5447 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5449 /* check pipline building state */
5450 __mmplayer_check_pipeline(player);
5451 __mmplayer_reset_gapless_state(player);
5453 /* NOTE : application should not wait for EOS after calling STOP */
5454 _mmplayer_cancel_eos_timer(player);
5457 player->seek_state = MMPLAYER_SEEK_NONE;
5460 ret = _mmplayer_gst_stop(player);
5462 if (ret != MM_ERROR_NONE)
5463 LOGE("failed to stop player.");
5471 _mmplayer_pause(MMHandleType hplayer)
5473 mmplayer_t *player = (mmplayer_t *)hplayer;
5474 gint64 pos_nsec = 0;
5475 gboolean async = FALSE;
5476 gint ret = MM_ERROR_NONE;
5480 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5482 /* check current state */
5483 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5485 /* check pipline building state */
5486 __mmplayer_check_pipeline(player);
5488 switch (MMPLAYER_CURRENT_STATE(player)) {
5489 case MM_PLAYER_STATE_READY:
5491 /* check prepare async or not.
5492 * In the case of streaming playback, it's recommned to avoid blocking wait.
5494 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5495 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5497 /* Changing back sync of rtspsrc to async */
5498 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5499 LOGD("async prepare working mode for rtsp");
5505 case MM_PLAYER_STATE_PLAYING:
5507 /* NOTE : store current point to overcome some bad operation
5508 *(returning zero when getting current position in paused state) of some
5511 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5512 LOGW("getting current position failed in paused");
5514 player->last_position = pos_nsec;
5516 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5517 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5518 This causes problem is position calculation during normal pause resume scenarios also.
5519 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5520 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5521 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5522 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5528 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5529 LOGD("doing async pause in case of ms buff src");
5533 /* pause pipeline */
5534 ret = _mmplayer_gst_pause(player, async);
5536 if (ret != MM_ERROR_NONE)
5537 LOGE("failed to pause player. ret : 0x%x", ret);
5539 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5540 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5541 LOGE("failed to update display_rotation");
5549 /* in case of streaming, pause could take long time.*/
5551 _mmplayer_abort_pause(MMHandleType hplayer)
5553 mmplayer_t *player = (mmplayer_t *)hplayer;
5554 int ret = MM_ERROR_NONE;
5558 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5560 player->pipeline->mainbin,
5561 MM_ERROR_PLAYER_NOT_INITIALIZED);
5563 LOGD("set the pipeline state to READY");
5565 /* set state to READY */
5566 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5567 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5568 if (ret != MM_ERROR_NONE) {
5569 LOGE("fail to change state to READY");
5570 return MM_ERROR_PLAYER_INTERNAL;
5573 LOGD("succeeded in changing state to READY");
5578 _mmplayer_resume(MMHandleType hplayer)
5580 mmplayer_t *player = (mmplayer_t *)hplayer;
5581 int ret = MM_ERROR_NONE;
5582 gboolean async = FALSE;
5586 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5588 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5589 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5590 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5594 /* Changing back sync mode rtspsrc to async */
5595 LOGD("async resume for rtsp case");
5599 /* check current state */
5600 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5602 ret = _mmplayer_gst_resume(player, async);
5603 if (ret != MM_ERROR_NONE)
5604 LOGE("failed to resume player.");
5606 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5607 LOGD("force resume even during buffering");
5608 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5617 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5619 mmplayer_t *player = (mmplayer_t *)hplayer;
5620 gint64 pos_nsec = 0;
5621 int ret = MM_ERROR_NONE;
5623 signed long long start = 0, stop = 0;
5624 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5627 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5628 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5630 /* The sound of video is not supported under 0.0 and over 2.0. */
5631 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5632 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5635 _mmplayer_set_mute(hplayer, mute);
5637 if (player->playback_rate == rate)
5638 return MM_ERROR_NONE;
5640 /* If the position is reached at start potion during fast backward, EOS is posted.
5641 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5643 player->playback_rate = rate;
5645 current_state = MMPLAYER_CURRENT_STATE(player);
5647 if (current_state != MM_PLAYER_STATE_PAUSED)
5648 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5650 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5652 if ((current_state == MM_PLAYER_STATE_PAUSED)
5653 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5654 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5655 pos_nsec = player->last_position;
5660 stop = GST_CLOCK_TIME_NONE;
5662 start = GST_CLOCK_TIME_NONE;
5666 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5667 player->playback_rate,
5669 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5670 GST_SEEK_TYPE_SET, start,
5671 GST_SEEK_TYPE_SET, stop)) {
5672 LOGE("failed to set speed playback");
5673 return MM_ERROR_PLAYER_SEEK;
5676 LOGD("succeeded to set speed playback as %0.1f", rate);
5680 return MM_ERROR_NONE;;
5684 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5686 mmplayer_t *player = (mmplayer_t *)hplayer;
5687 int ret = MM_ERROR_NONE;
5691 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5693 /* check pipline building state */
5694 __mmplayer_check_pipeline(player);
5696 ret = _mmplayer_gst_set_position(player, position, FALSE);
5704 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5706 mmplayer_t *player = (mmplayer_t *)hplayer;
5707 int ret = MM_ERROR_NONE;
5709 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5710 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5712 if (g_strrstr(player->type, "video/mpegts"))
5713 __mmplayer_update_duration_value(player);
5715 *duration = player->duration;
5720 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5722 mmplayer_t *player = (mmplayer_t *)hplayer;
5723 int ret = MM_ERROR_NONE;
5725 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5727 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5733 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5735 mmplayer_t *player = (mmplayer_t *)hplayer;
5736 int ret = MM_ERROR_NONE;
5740 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5742 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5750 __mmplayer_is_midi_type(gchar *str_caps)
5752 if ((g_strrstr(str_caps, "audio/midi")) ||
5753 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5754 (g_strrstr(str_caps, "application/x-smaf")) ||
5755 (g_strrstr(str_caps, "audio/x-imelody")) ||
5756 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5757 (g_strrstr(str_caps, "audio/xmf")) ||
5758 (g_strrstr(str_caps, "audio/mxmf"))) {
5767 __mmplayer_is_only_mp3_type(gchar *str_caps)
5769 if (g_strrstr(str_caps, "application/x-id3") ||
5770 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5776 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5778 GstStructure *caps_structure = NULL;
5779 gint samplerate = 0;
5783 MMPLAYER_RETURN_IF_FAIL(player && caps);
5785 caps_structure = gst_caps_get_structure(caps, 0);
5787 /* set stream information */
5788 gst_structure_get_int(caps_structure, "rate", &samplerate);
5789 gst_structure_get_int(caps_structure, "channels", &channels);
5791 mm_player_set_attribute((MMHandleType)player, NULL,
5792 "content_audio_samplerate", samplerate,
5793 "content_audio_channels", channels, NULL);
5795 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5799 __mmplayer_update_content_type_info(mmplayer_t *player)
5802 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5804 if (__mmplayer_is_midi_type(player->type)) {
5805 player->bypass_audio_effect = TRUE;
5809 if (!player->streamer) {
5810 LOGD("no need to check streaming type");
5814 if (g_strrstr(player->type, "application/x-hls")) {
5815 /* If it can't know exact type when it parses uri because of redirection case,
5816 * it will be fixed by typefinder or when doing autoplugging.
5818 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5819 player->streamer->is_adaptive_streaming = TRUE;
5820 } else if (g_strrstr(player->type, "application/dash+xml")) {
5821 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5822 player->streamer->is_adaptive_streaming = TRUE;
5825 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5826 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5827 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5829 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5830 if (player->streamer->is_adaptive_streaming)
5831 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5833 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5837 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5842 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5843 GstCaps *caps, gpointer data)
5845 mmplayer_t *player = (mmplayer_t *)data;
5850 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5852 /* store type string */
5853 MMPLAYER_FREEIF(player->type);
5854 player->type = gst_caps_to_string(caps);
5856 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5857 player, player->type, probability, gst_caps_get_size(caps));
5859 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5860 (g_strrstr(player->type, "audio/x-raw-int"))) {
5861 LOGE("not support media format");
5863 if (player->msg_posted == FALSE) {
5864 MMMessageParamType msg_param;
5865 memset(&msg_param, 0, sizeof(MMMessageParamType));
5867 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5868 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5870 /* don't post more if one was sent already */
5871 player->msg_posted = TRUE;
5876 __mmplayer_update_content_type_info(player);
5878 pad = gst_element_get_static_pad(tf, "src");
5880 LOGE("fail to get typefind src pad.");
5884 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
5885 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5886 gboolean async = FALSE;
5887 LOGE("failed to autoplug %s", player->type);
5889 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5891 if (async && player->msg_posted == FALSE)
5892 __mmplayer_handle_missed_plugin(player);
5896 gst_object_unref(GST_OBJECT(pad));
5902 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5904 GstElement *decodebin = NULL;
5908 /* create decodebin */
5909 decodebin = gst_element_factory_make("decodebin", NULL);
5912 LOGE("fail to create decodebin");
5916 /* raw pad handling signal */
5917 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5918 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5920 /* no-more-pad pad handling signal */
5921 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5922 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
5924 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5925 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
5927 /* This signal is emitted when a pad for which there is no further possible
5928 decoding is added to the decodebin.*/
5929 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5930 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
5932 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5933 before looking for any elements that can handle that stream.*/
5934 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5935 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5937 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5938 before looking for any elements that can handle that stream.*/
5939 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5940 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
5942 /* This signal is emitted once decodebin has finished decoding all the data.*/
5943 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5944 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
5946 /* This signal is emitted when a element is added to the bin.*/
5947 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5948 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
5955 __mmplayer_gst_make_queue2(mmplayer_t *player)
5957 GstElement *queue2 = NULL;
5958 gint64 dur_bytes = 0L;
5959 mmplayer_gst_element_t *mainbin = NULL;
5960 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5963 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5965 mainbin = player->pipeline->mainbin;
5967 queue2 = gst_element_factory_make("queue2", "queue2");
5969 LOGE("failed to create buffering queue element");
5973 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5974 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5976 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5978 /* NOTE : in case of ts streaming, player could not get the correct duration info *
5979 * skip the pull mode(file or ring buffering) setting. */
5980 if (dur_bytes > 0) {
5981 if (!g_strrstr(player->type, "video/mpegts")) {
5982 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5983 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5989 _mm_player_streaming_set_queue2(player->streamer,
5993 (guint64)dur_bytes); /* no meaning at the moment */
5999 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6001 mmplayer_gst_element_t *mainbin = NULL;
6002 GstElement *decodebin = NULL;
6003 GstElement *queue2 = NULL;
6004 GstPad *sinkpad = NULL;
6005 GstPad *qsrcpad = NULL;
6008 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6010 mainbin = player->pipeline->mainbin;
6012 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6014 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6015 LOGW("need to check: muxed buffer is not null");
6018 queue2 = __mmplayer_gst_make_queue2(player);
6020 LOGE("failed to make queue2");
6024 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6025 LOGE("failed to add buffering queue");
6029 sinkpad = gst_element_get_static_pad(queue2, "sink");
6030 qsrcpad = gst_element_get_static_pad(queue2, "src");
6032 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6033 LOGE("failed to link [%s:%s]-[%s:%s]",
6034 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6038 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6039 LOGE("failed to sync queue2 state with parent");
6043 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6044 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6048 gst_object_unref(GST_OBJECT(sinkpad));
6052 /* create decodebin */
6053 decodebin = _mmplayer_gst_make_decodebin(player);
6055 LOGE("failed to make decodebin");
6059 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6060 LOGE("failed to add decodebin");
6064 /* to force caps on the decodebin element and avoid reparsing stuff by
6065 * typefind. It also avoids a deadlock in the way typefind activates pads in
6066 * the state change */
6067 g_object_set(decodebin, "sink-caps", caps, NULL);
6069 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6071 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6072 LOGE("failed to link [%s:%s]-[%s:%s]",
6073 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6077 gst_object_unref(GST_OBJECT(sinkpad));
6079 gst_object_unref(GST_OBJECT(qsrcpad));
6082 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6083 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6085 /* set decodebin property about buffer in streaming playback. *
6086 * in case of HLS/DASH, it does not need to have big buffer *
6087 * because it is kind of adaptive streaming. */
6088 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6089 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6090 gint high_percent = 0;
6092 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6093 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6095 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6097 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6099 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6100 "high-percent", high_percent,
6101 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6102 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6103 "max-size-buffers", 0, NULL); // disable or automatic
6106 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6107 LOGE("failed to sync decodebin state with parent");
6118 gst_object_unref(GST_OBJECT(sinkpad));
6121 gst_object_unref(GST_OBJECT(qsrcpad));
6124 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6125 * You need to explicitly set elements to the NULL state before
6126 * dropping the final reference, to allow them to clean up.
6128 gst_element_set_state(queue2, GST_STATE_NULL);
6130 /* And, it still has a parent "player".
6131 * You need to let the parent manage the object instead of unreffing the object directly.
6133 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6134 gst_object_unref(queue2);
6139 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6140 * You need to explicitly set elements to the NULL state before
6141 * dropping the final reference, to allow them to clean up.
6143 gst_element_set_state(decodebin, GST_STATE_NULL);
6145 /* And, it still has a parent "player".
6146 * You need to let the parent manage the object instead of unreffing the object directly.
6149 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6150 gst_object_unref(decodebin);
6158 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6162 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6163 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6165 LOGD("class : %s, mime : %s", factory_class, mime);
6167 /* add missing plugin */
6168 /* NOTE : msl should check missing plugin for image mime type.
6169 * Some motion jpeg clips can have playable audio track.
6170 * So, msl have to play audio after displaying popup written video format not supported.
6172 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6173 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6174 LOGD("not found demuxer");
6175 player->not_found_demuxer = TRUE;
6176 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6182 if (!g_strrstr(factory_class, "Demuxer")) {
6183 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6184 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6185 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6187 /* check that clip have multi tracks or not */
6188 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6189 LOGD("video plugin is already linked");
6191 LOGW("add VIDEO to missing plugin");
6192 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6193 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6195 } else if (g_str_has_prefix(mime, "audio")) {
6196 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6197 LOGD("audio plugin is already linked");
6199 LOGW("add AUDIO to missing plugin");
6200 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6201 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6209 return MM_ERROR_NONE;
6213 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6215 mmplayer_t *player = (mmplayer_t *)data;
6219 MMPLAYER_RETURN_IF_FAIL(player);
6221 /* remove fakesink. */
6222 if (!_mmplayer_gst_remove_fakesink(player,
6223 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6224 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6225 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6226 * source element are not same. To overcome this situation, this function will called
6227 * several places and several times. Therefore, this is not an error case.
6232 LOGD("[handle: %p] pipeline has completely constructed", player);
6234 if ((player->ini.async_start) &&
6235 (player->msg_posted == FALSE) &&
6236 (player->cmd >= MMPLAYER_COMMAND_START))
6237 __mmplayer_handle_missed_plugin(player);
6239 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6243 __mmplayer_check_profile(void)
6246 static int profile_tv = -1;
6248 if (__builtin_expect(profile_tv != -1, 1))
6251 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6252 switch (*profileName) {
6267 __mmplayer_get_next_uri(mmplayer_t *player)
6269 mmplayer_parse_profile_t profile;
6271 guint num_of_list = 0;
6274 num_of_list = g_list_length(player->uri_info.uri_list);
6275 uri_idx = player->uri_info.uri_idx;
6277 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6278 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6279 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6281 LOGW("next uri does not exist");
6285 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6286 LOGE("failed to parse profile");
6290 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6291 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6292 LOGW("uri type is not supported(%d)", profile.uri_type);
6296 LOGD("success to find next uri %d", uri_idx);
6300 if (!uri || uri_idx == num_of_list) {
6301 LOGE("failed to find next uri");
6305 player->uri_info.uri_idx = uri_idx;
6306 if (mm_player_set_attribute((MMHandleType)player, NULL,
6307 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6308 LOGE("failed to set attribute");
6312 SECURE_LOGD("next playback uri: %s", uri);
6317 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6319 #define REPEAT_COUNT_INFINITE -1
6320 #define REPEAT_COUNT_MIN 2
6321 #define ORIGINAL_URI_ONLY 1
6323 MMHandleType attrs = 0;
6327 guint num_of_uri = 0;
6328 int profile_tv = -1;
6332 LOGD("checking for gapless play option");
6334 if (player->build_audio_offload) {
6335 LOGE("offload path is not supportable.");
6339 if (player->pipeline->textbin) {
6340 LOGE("subtitle path is enabled. gapless play is not supported.");
6344 attrs = MMPLAYER_GET_ATTRS(player);
6346 LOGE("fail to get attributes.");
6350 mm_attrs_multiple_get(player->attrs, NULL,
6351 "content_video_found", &video,
6352 "profile_play_count", &count,
6353 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6355 /* gapless playback is not supported in case of video at TV profile. */
6356 profile_tv = __mmplayer_check_profile();
6357 if (profile_tv && video) {
6358 LOGW("not support video gapless playback");
6362 /* check repeat count in case of audio */
6364 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6365 LOGW("gapless is disabled");
6369 num_of_uri = g_list_length(player->uri_info.uri_list);
6371 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6373 if (num_of_uri == ORIGINAL_URI_ONLY) {
6374 /* audio looping path */
6375 if (count >= REPEAT_COUNT_MIN) {
6376 /* decrease play count */
6377 /* we succeeded to rewind. update play count and then wait for next EOS */
6379 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6380 } else if (count != REPEAT_COUNT_INFINITE) {
6381 LOGD("there is no next uri and no repeat");
6384 LOGD("looping cnt %d", count);
6386 /* gapless playback path */
6387 if (!__mmplayer_get_next_uri(player)) {
6388 LOGE("failed to get next uri");
6395 LOGE("unable to play gapless path. EOS will be posted soon");
6400 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6402 mmplayer_selector_t *selector = &player->selector[type];
6403 mmplayer_gst_element_t *sinkbin = NULL;
6404 main_element_id_e selectorId = MMPLAYER_M_NUM;
6405 main_element_id_e sinkId = MMPLAYER_M_NUM;
6406 GstPad *srcpad = NULL;
6407 GstPad *sinkpad = NULL;
6408 gboolean send_notice = FALSE;
6411 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6413 LOGD("type %d", type);
6416 case MM_PLAYER_TRACK_TYPE_AUDIO:
6417 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6418 sinkId = MMPLAYER_A_BIN;
6419 sinkbin = player->pipeline->audiobin;
6421 case MM_PLAYER_TRACK_TYPE_VIDEO:
6422 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6423 sinkId = MMPLAYER_V_BIN;
6424 sinkbin = player->pipeline->videobin;
6427 case MM_PLAYER_TRACK_TYPE_TEXT:
6428 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6429 sinkId = MMPLAYER_T_BIN;
6430 sinkbin = player->pipeline->textbin;
6433 LOGE("requested type is not supportable");
6438 if (player->pipeline->mainbin[selectorId].gst) {
6441 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6443 if (selector->event_probe_id != 0)
6444 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6445 selector->event_probe_id = 0;
6447 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6448 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6450 if (srcpad && sinkpad) {
6451 /* after getting drained signal there is no data flows, so no need to do pad_block */
6452 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6453 gst_pad_unlink(srcpad, sinkpad);
6455 /* send custom event to sink pad to handle it at video sink */
6457 LOGD("send custom event to sinkpad");
6458 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6459 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6460 gst_pad_send_event(sinkpad, event);
6464 gst_object_unref(sinkpad);
6467 gst_object_unref(srcpad);
6470 LOGD("selector release");
6472 /* release and unref requests pad from the selector */
6473 for (n = 0; n < selector->channels->len; n++) {
6474 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6475 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6477 g_ptr_array_set_size(selector->channels, 0);
6479 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6480 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6482 player->pipeline->mainbin[selectorId].gst = NULL;
6490 __mmplayer_deactivate_old_path(mmplayer_t *player)
6493 MMPLAYER_RETURN_IF_FAIL(player);
6495 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6496 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6497 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6498 LOGE("deactivate selector error");
6502 _mmplayer_track_destroy(player);
6503 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6505 if (player->streamer) {
6506 _mm_player_streaming_initialize(player->streamer, FALSE);
6507 _mm_player_streaming_destroy(player->streamer);
6508 player->streamer = NULL;
6511 MMPLAYER_PLAYBACK_LOCK(player);
6512 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6519 if (!player->msg_posted) {
6520 MMMessageParamType msg = {0,};
6523 msg.code = MM_ERROR_PLAYER_INTERNAL;
6524 LOGE("gapless_uri_play> deactivate error");
6526 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6527 player->msg_posted = TRUE;
6533 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6535 int result = MM_ERROR_NONE;
6536 mmplayer_t *player = (mmplayer_t *)hplayer;
6539 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6540 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6542 if (mm_player_set_attribute(hplayer, NULL,
6543 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6544 LOGE("failed to set attribute");
6545 result = MM_ERROR_PLAYER_INTERNAL;
6547 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6548 LOGE("failed to add the original uri in the uri list.");
6556 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6558 mmplayer_t *player = (mmplayer_t *)hplayer;
6559 guint num_of_list = 0;
6563 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6564 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6566 if (player->pipeline && player->pipeline->textbin) {
6567 LOGE("subtitle path is enabled.");
6568 return MM_ERROR_PLAYER_INVALID_STATE;
6571 num_of_list = g_list_length(player->uri_info.uri_list);
6573 if (is_first_path) {
6574 if (num_of_list == 0) {
6575 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6576 SECURE_LOGD("add original path : %s", uri);
6578 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6579 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6581 SECURE_LOGD("change original path : %s", uri);
6584 MMHandleType attrs = 0;
6585 attrs = MMPLAYER_GET_ATTRS(player);
6587 if (num_of_list == 0) {
6588 char *original_uri = NULL;
6591 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6593 if (!original_uri) {
6594 LOGE("there is no original uri.");
6595 return MM_ERROR_PLAYER_INVALID_STATE;
6598 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6599 player->uri_info.uri_idx = 0;
6601 SECURE_LOGD("add original path at first : %s", original_uri);
6605 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6606 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6610 return MM_ERROR_NONE;
6614 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6616 mmplayer_t *player = (mmplayer_t *)hplayer;
6617 char *next_uri = NULL;
6618 guint num_of_list = 0;
6621 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6623 num_of_list = g_list_length(player->uri_info.uri_list);
6625 if (num_of_list > 0) {
6626 gint uri_idx = player->uri_info.uri_idx;
6628 if (uri_idx < num_of_list-1)
6633 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6634 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6636 *uri = g_strdup(next_uri);
6640 return MM_ERROR_NONE;
6644 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6645 GstCaps *caps, gpointer data)
6647 mmplayer_t *player = (mmplayer_t *)data;
6648 const gchar *klass = NULL;
6649 const gchar *mime = NULL;
6650 gchar *caps_str = NULL;
6652 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6653 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6654 caps_str = gst_caps_to_string(caps);
6656 LOGW("unknown type of caps : %s from %s",
6657 caps_str, GST_ELEMENT_NAME(elem));
6659 MMPLAYER_FREEIF(caps_str);
6661 /* There is no available codec. */
6662 __mmplayer_check_not_supported_codec(player, klass, mime);
6666 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6667 GstCaps *caps, gpointer data)
6669 mmplayer_t *player = (mmplayer_t *)data;
6670 const char *mime = NULL;
6671 gboolean ret = TRUE;
6673 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6674 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6676 if (g_str_has_prefix(mime, "audio")) {
6677 GstStructure *caps_structure = NULL;
6678 gint samplerate = 0;
6680 gchar *caps_str = NULL;
6682 caps_structure = gst_caps_get_structure(caps, 0);
6683 gst_structure_get_int(caps_structure, "rate", &samplerate);
6684 gst_structure_get_int(caps_structure, "channels", &channels);
6686 if ((channels > 0 && samplerate == 0)) {
6687 LOGD("exclude audio...");
6691 caps_str = gst_caps_to_string(caps);
6692 /* set it directly because not sent by TAG */
6693 if (g_strrstr(caps_str, "mobile-xmf"))
6694 mm_player_set_attribute((MMHandleType)player, NULL,
6695 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6697 MMPLAYER_FREEIF(caps_str);
6698 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6699 MMMessageParamType msg_param;
6700 memset(&msg_param, 0, sizeof(MMMessageParamType));
6701 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6702 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6703 LOGD("video file is not supported on this device");
6705 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6706 LOGD("already video linked");
6709 LOGD("found new stream");
6716 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6718 gboolean ret = TRUE;
6719 GDBusConnection *conn = NULL;
6721 GVariant *result = NULL;
6722 const gchar *dbus_device_type = NULL;
6723 const gchar *dbus_ret = NULL;
6726 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6728 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6734 result = g_dbus_connection_call_sync(conn,
6735 "org.pulseaudio.Server",
6736 "/org/pulseaudio/StreamManager",
6737 "org.pulseaudio.StreamManager",
6738 "GetCurrentMediaRoutingPath",
6739 g_variant_new("(s)", "out"),
6740 G_VARIANT_TYPE("(ss)"),
6741 G_DBUS_CALL_FLAGS_NONE,
6745 if (!result || err) {
6746 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6752 /* device type is listed in stream-map.json at mmfw-sysconf */
6753 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6755 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6756 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6761 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6762 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6763 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6764 LOGD("audio offload is supportable");
6770 LOGD("audio offload is not supportable");
6774 g_variant_unref(result);
6775 g_object_unref(conn);
6780 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6782 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6783 gint64 position = 0;
6785 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6786 player->pipeline && player->pipeline->mainbin);
6788 MMPLAYER_CMD_LOCK(player);
6789 current_state = MMPLAYER_CURRENT_STATE(player);
6791 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6792 LOGW("getting current position failed in paused");
6794 _mmplayer_unrealize((MMHandleType)player);
6795 _mmplayer_realize((MMHandleType)player);
6797 _mmplayer_set_position((MMHandleType)player, position);
6799 /* async not to be blocked in streaming case */
6800 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6802 _mmplayer_pause((MMHandleType)player);
6804 if (current_state == MM_PLAYER_STATE_PLAYING)
6805 _mmplayer_start((MMHandleType)player);
6806 MMPLAYER_CMD_UNLOCK(player);
6808 LOGD("rebuilding audio pipeline is completed.");
6811 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6813 mmplayer_t *player = (mmplayer_t *)user_data;
6814 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6815 gboolean is_supportable = FALSE;
6817 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6818 LOGW("failed to get device type");
6820 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6822 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6823 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6824 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6825 LOGD("ignore this dev connected info");
6829 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6830 if (player->build_audio_offload == is_supportable) {
6831 LOGD("keep current pipeline without re-building");
6835 /* rebuild pipeline */
6836 LOGD("re-build pipeline - offload: %d", is_supportable);
6837 player->build_audio_offload = FALSE;
6838 __mmplayer_rebuild_audio_pipeline(player);
6844 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6846 unsigned int id = 0;
6848 if (player->audio_device_cb_id != 0) {
6849 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6853 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6854 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6855 LOGD("added device connected cb (%u)", id);
6856 player->audio_device_cb_id = id;
6858 LOGW("failed to add device connected cb");
6865 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
6867 mmplayer_t *player = (mmplayer_t *)hplayer;
6870 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6871 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
6873 *activated = player->build_audio_offload;
6875 LOGD("offload activated : %d", (int)*activated);
6878 return MM_ERROR_NONE;
6882 __mmplayer_is_offload_supported_type(mmplayer_t *player)
6885 this function need to be updated according to the supported media format
6886 @see player->ini.audio_offload_media_format */
6888 if (__mmplayer_is_only_mp3_type(player->type)) {
6889 LOGD("offload supportable media format type");
6897 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6899 gboolean ret = FALSE;
6900 GstElementFactory *factory = NULL;
6903 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6905 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6906 if (!__mmplayer_is_offload_supported_type(player))
6909 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6910 LOGD("there is no audio offload sink");
6914 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6915 LOGW("there is no audio device type to support offload");
6919 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6921 LOGW("there is no installed audio offload sink element");
6924 gst_object_unref(factory);
6926 if (__mmplayer_acquire_hw_resource(player,
6927 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6928 LOGE("failed to acquire audio offload decoder resource");
6932 if (!__mmplayer_add_audio_device_connected_cb(player))
6935 if (!__mmplayer_is_audio_offload_device_type(player))
6938 LOGD("audio offload can be built");
6943 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6949 static GstAutoplugSelectResult
6950 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6952 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6954 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6955 int audio_offload = 0;
6957 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6958 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6960 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6961 LOGD("expose audio path to build offload output path");
6962 player->build_audio_offload = TRUE;
6963 /* update codec info */
6964 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6965 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6966 player->audiodec_linked = 1;
6968 ret = GST_AUTOPLUG_SELECT_EXPOSE;
6972 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6974 LOGD("audio codec type: %d", codec_type);
6975 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6976 /* sw codec will be skipped */
6977 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6978 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6979 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6980 ret = GST_AUTOPLUG_SELECT_SKIP;
6984 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6985 /* hw codec will be skipped */
6986 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6987 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6988 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6989 ret = GST_AUTOPLUG_SELECT_SKIP;
6994 /* set stream information */
6995 if (!player->audiodec_linked)
6996 __mmplayer_set_audio_attrs(player, caps);
6998 /* update codec info */
6999 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7000 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7001 player->audiodec_linked = 1;
7003 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7005 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7007 LOGD("video codec type: %d", codec_type);
7008 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7009 /* sw codec is skipped */
7010 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7011 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7012 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7013 ret = GST_AUTOPLUG_SELECT_SKIP;
7017 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7018 /* hw codec is skipped */
7019 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7020 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7021 ret = GST_AUTOPLUG_SELECT_SKIP;
7026 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7027 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7029 /* mark video decoder for acquire */
7030 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7031 LOGW("video decoder resource is already acquired, skip it.");
7032 ret = GST_AUTOPLUG_SELECT_SKIP;
7036 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7037 LOGE("failed to acquire video decoder resource");
7038 ret = GST_AUTOPLUG_SELECT_SKIP;
7041 player->interrupted_by_resource = FALSE;
7044 /* update codec info */
7045 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7046 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7047 player->videodec_linked = 1;
7055 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7056 GstCaps *caps, GstElementFactory *factory, gpointer data)
7058 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7059 mmplayer_t *player = (mmplayer_t *)data;
7061 gchar *factory_name = NULL;
7062 gchar *caps_str = NULL;
7063 const gchar *klass = NULL;
7066 factory_name = GST_OBJECT_NAME(factory);
7067 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7068 caps_str = gst_caps_to_string(caps);
7070 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7072 /* store type string */
7073 if (player->type == NULL) {
7074 player->type = gst_caps_to_string(caps);
7075 __mmplayer_update_content_type_info(player);
7078 /* filtering exclude keyword */
7079 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7080 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7081 LOGW("skipping [%s] by exculde keyword [%s]",
7082 factory_name, player->ini.exclude_element_keyword[idx]);
7084 result = GST_AUTOPLUG_SELECT_SKIP;
7089 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7090 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7091 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7092 factory_name, player->ini.unsupported_codec_keyword[idx]);
7093 result = GST_AUTOPLUG_SELECT_SKIP;
7098 /* exclude webm format */
7099 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7100 * because webm format is not supportable.
7101 * If webm is disabled in "autoplug-continue", there is no state change
7102 * failure or error because the decodebin will expose the pad directly.
7103 * It make MSL invoke _prepare_async_callback.
7104 * So, we need to disable webm format in "autoplug-select" */
7105 if (caps_str && strstr(caps_str, "webm")) {
7106 LOGW("webm is not supported");
7107 result = GST_AUTOPLUG_SELECT_SKIP;
7111 /* check factory class for filtering */
7112 /* NOTE : msl don't need to use image plugins.
7113 * So, those plugins should be skipped for error handling.
7115 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7116 LOGD("skipping [%s] by not required", factory_name);
7117 result = GST_AUTOPLUG_SELECT_SKIP;
7121 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7122 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7123 // TO CHECK : subtitle if needed, add subparse exception.
7124 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7125 result = GST_AUTOPLUG_SELECT_SKIP;
7129 if (g_strrstr(factory_name, "mpegpsdemux")) {
7130 LOGD("skipping PS container - not support");
7131 result = GST_AUTOPLUG_SELECT_SKIP;
7135 if (g_strrstr(factory_name, "mssdemux"))
7136 player->smooth_streaming = TRUE;
7138 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7139 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7142 GstStructure *str = NULL;
7143 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7145 /* don't make video because of not required */
7146 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7147 (!player->set_mode.video_export)) {
7148 LOGD("no need video decoding, expose pad");
7149 result = GST_AUTOPLUG_SELECT_EXPOSE;
7153 /* get w/h for omx state-tune */
7154 /* FIXME: deprecated? */
7155 str = gst_caps_get_structure(caps, 0);
7156 gst_structure_get_int(str, "width", &width);
7159 if (player->v_stream_caps) {
7160 gst_caps_unref(player->v_stream_caps);
7161 player->v_stream_caps = NULL;
7164 player->v_stream_caps = gst_caps_copy(caps);
7165 LOGD("take caps for video state tune");
7166 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7170 if (g_strrstr(klass, "Codec/Decoder")) {
7171 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7172 if (result != GST_AUTOPLUG_SELECT_TRY) {
7173 LOGW("skip add decoder");
7179 MMPLAYER_FREEIF(caps_str);
7185 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7188 //mmplayer_t *player = (mmplayer_t *)data;
7189 GstCaps *caps = NULL;
7191 LOGD("[Decodebin2] pad-removed signal");
7193 caps = gst_pad_query_caps(new_pad, NULL);
7195 LOGW("query caps is NULL");
7199 gchar *caps_str = NULL;
7200 caps_str = gst_caps_to_string(caps);
7202 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7204 MMPLAYER_FREEIF(caps_str);
7205 gst_caps_unref(caps);
7209 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7211 mmplayer_t *player = (mmplayer_t *)data;
7212 GstIterator *iter = NULL;
7213 GValue item = { 0, };
7215 gboolean done = FALSE;
7216 gboolean is_all_drained = TRUE;
7219 MMPLAYER_RETURN_IF_FAIL(player);
7221 LOGD("got drained signal");
7223 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7224 LOGW("Fail to get cmd lock");
7228 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7229 !__mmplayer_verify_gapless_play_path(player)) {
7230 LOGD("decoding is finished.");
7231 __mmplayer_reset_gapless_state(player);
7232 MMPLAYER_CMD_UNLOCK(player);
7236 player->gapless.reconfigure = TRUE;
7238 /* check decodebin src pads whether they received EOS or not */
7239 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7242 switch (gst_iterator_next(iter, &item)) {
7243 case GST_ITERATOR_OK:
7244 pad = g_value_get_object(&item);
7245 if (pad && !GST_PAD_IS_EOS(pad)) {
7246 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7247 is_all_drained = FALSE;
7250 g_value_reset(&item);
7252 case GST_ITERATOR_RESYNC:
7253 gst_iterator_resync(iter);
7255 case GST_ITERATOR_ERROR:
7256 case GST_ITERATOR_DONE:
7261 g_value_unset(&item);
7262 gst_iterator_free(iter);
7264 if (!is_all_drained) {
7265 LOGD("Wait util the all pads get EOS.");
7266 MMPLAYER_CMD_UNLOCK(player);
7271 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7272 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7274 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7275 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7276 __mmplayer_deactivate_old_path(player);
7277 MMPLAYER_CMD_UNLOCK(player);
7283 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7285 mmplayer_t *player = (mmplayer_t *)data;
7286 const gchar *klass = NULL;
7287 gchar *factory_name = NULL;
7289 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7290 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7292 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7294 if (__mmplayer_add_dump_buffer_probe(player, element))
7295 LOGD("add buffer probe");
7297 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7298 gchar *selected = NULL;
7299 selected = g_strdup(GST_ELEMENT_NAME(element));
7300 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7303 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7304 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7305 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7307 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7308 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7310 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7311 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7312 "max-video-width", player->adaptive_info.limit.width,
7313 "max-video-height", player->adaptive_info.limit.height, NULL);
7315 } else if (g_strrstr(klass, "Demuxer")) {
7317 LOGD("plugged element is demuxer. take it");
7319 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7320 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7323 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7324 int surface_type = 0;
7326 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7329 // to support trust-zone only
7330 if (g_strrstr(factory_name, "asfdemux")) {
7331 LOGD("set file-location %s", player->profile.uri);
7332 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7333 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7334 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7335 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7336 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7337 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7338 (__mmplayer_is_only_mp3_type(player->type))) {
7339 LOGD("[mpegaudioparse] set streaming pull mode.");
7340 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7342 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7343 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7346 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7347 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7348 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7350 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7351 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7353 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7354 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7355 (MMPLAYER_IS_DASH_STREAMING(player))) {
7356 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7357 _mm_player_streaming_set_multiqueue(player->streamer, element);
7358 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7367 __mmplayer_release_misc(mmplayer_t *player)
7370 bool cur_mode = player->set_mode.rich_audio;
7373 MMPLAYER_RETURN_IF_FAIL(player);
7375 player->video_decoded_cb = NULL;
7376 player->video_decoded_cb_user_param = NULL;
7377 player->video_stream_prerolled = false;
7379 player->audio_decoded_cb = NULL;
7380 player->audio_decoded_cb_user_param = NULL;
7381 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7383 player->audio_stream_changed_cb = NULL;
7384 player->audio_stream_changed_cb_user_param = NULL;
7386 player->sent_bos = FALSE;
7387 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7389 player->seek_state = MMPLAYER_SEEK_NONE;
7391 player->total_bitrate = 0;
7392 player->total_maximum_bitrate = 0;
7394 player->not_found_demuxer = 0;
7396 player->last_position = 0;
7397 player->duration = 0;
7398 player->http_content_size = 0;
7399 player->not_supported_codec = MISSING_PLUGIN_NONE;
7400 player->can_support_codec = FOUND_PLUGIN_NONE;
7401 player->pending_seek.is_pending = false;
7402 player->pending_seek.pos = 0;
7403 player->msg_posted = FALSE;
7404 player->has_many_types = FALSE;
7405 player->is_subtitle_force_drop = FALSE;
7406 player->play_subtitle = FALSE;
7407 player->adjust_subtitle_pos = 0;
7408 player->has_closed_caption = FALSE;
7409 player->set_mode.video_export = false;
7410 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7411 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7413 player->set_mode.rich_audio = cur_mode;
7415 if (player->audio_device_cb_id > 0 &&
7416 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7417 LOGW("failed to remove audio device_connected_callback");
7418 player->audio_device_cb_id = 0;
7420 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7421 player->bitrate[i] = 0;
7422 player->maximum_bitrate[i] = 0;
7425 /* free memory related to audio effect */
7426 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7428 if (player->adaptive_info.var_list) {
7429 g_list_free_full(player->adaptive_info.var_list, g_free);
7430 player->adaptive_info.var_list = NULL;
7433 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7434 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7435 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7437 /* Reset video360 settings to their defaults in case if the pipeline is to be
7440 player->video360_metadata.is_spherical = -1;
7441 player->is_openal_plugin_used = FALSE;
7443 player->is_content_spherical = FALSE;
7444 player->is_video360_enabled = TRUE;
7445 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7446 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7447 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7448 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7449 player->video360_zoom = 1.0f;
7450 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7451 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7453 player->sound.rg_enable = false;
7455 __mmplayer_initialize_video_roi(player);
7460 __mmplayer_release_misc_post(mmplayer_t *player)
7462 char *original_uri = NULL;
7465 /* player->pipeline is already released before. */
7467 MMPLAYER_RETURN_IF_FAIL(player);
7469 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7471 /* clean found audio decoders */
7472 if (player->audio_decoders) {
7473 GList *a_dec = player->audio_decoders;
7474 for (; a_dec; a_dec = g_list_next(a_dec)) {
7475 gchar *name = a_dec->data;
7476 MMPLAYER_FREEIF(name);
7478 g_list_free(player->audio_decoders);
7479 player->audio_decoders = NULL;
7482 /* clean the uri list except original uri */
7483 if (player->uri_info.uri_list) {
7484 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7487 LOGW("failed to get original uri info");
7489 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7490 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7492 GList *uri_list = player->uri_info.uri_list;
7493 for (; uri_list; uri_list = g_list_next(uri_list)) {
7494 gchar *uri = uri_list->data;
7495 MMPLAYER_FREEIF(uri);
7497 g_list_free(player->uri_info.uri_list);
7498 player->uri_info.uri_list = NULL;
7501 /* clear the audio stream buffer list */
7502 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7504 /* clear the video stream bo list */
7505 __mmplayer_video_stream_destroy_bo_list(player);
7506 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7508 if (player->profile.input_mem.buf) {
7509 free(player->profile.input_mem.buf);
7510 player->profile.input_mem.buf = NULL;
7512 player->profile.input_mem.len = 0;
7513 player->profile.input_mem.offset = 0;
7515 player->uri_info.uri_idx = 0;
7520 __mmplayer_check_subtitle(mmplayer_t *player)
7522 MMHandleType attrs = 0;
7523 char *subtitle_uri = NULL;
7527 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7529 /* get subtitle attribute */
7530 attrs = MMPLAYER_GET_ATTRS(player);
7534 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7535 if (!subtitle_uri || !strlen(subtitle_uri))
7538 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7539 player->is_external_subtitle_present = TRUE;
7547 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7549 MMPLAYER_RETURN_IF_FAIL(player);
7551 if (player->eos_timer) {
7552 LOGD("cancel eos timer");
7553 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7554 player->eos_timer = 0;
7561 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7565 MMPLAYER_RETURN_IF_FAIL(player);
7566 MMPLAYER_RETURN_IF_FAIL(sink);
7568 player->sink_elements = g_list_append(player->sink_elements, sink);
7574 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7578 MMPLAYER_RETURN_IF_FAIL(player);
7579 MMPLAYER_RETURN_IF_FAIL(sink);
7581 player->sink_elements = g_list_remove(player->sink_elements, sink);
7587 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7588 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7590 mmplayer_signal_item_t *item = NULL;
7593 MMPLAYER_RETURN_IF_FAIL(player);
7595 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7596 LOGE("invalid signal type [%d]", type);
7600 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7602 LOGE("cannot connect signal [%s]", signal);
7607 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7608 player->signals[type] = g_list_append(player->signals[type], item);
7614 /* NOTE : be careful with calling this api. please refer to below glib comment
7615 * glib comment : Note that there is a bug in GObject that makes this function much
7616 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7617 * will no longer be called, but, the signal handler is not currently disconnected.
7618 * If the instance is itself being freed at the same time than this doesn't matter,
7619 * since the signal will automatically be removed, but if instance persists,
7620 * then the signal handler will leak. You should not remove the signal yourself
7621 * because in a future versions of GObject, the handler will automatically be
7624 * It's possible to work around this problem in a way that will continue to work
7625 * with future versions of GObject by checking that the signal handler is still
7626 * connected before disconnected it:
7628 * if (g_signal_handler_is_connected(instance, id))
7629 * g_signal_handler_disconnect(instance, id);
7632 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7634 GList *sig_list = NULL;
7635 mmplayer_signal_item_t *item = NULL;
7639 MMPLAYER_RETURN_IF_FAIL(player);
7641 LOGD("release signals type : %d", type);
7643 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7644 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7645 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7646 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7647 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7648 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7652 sig_list = player->signals[type];
7654 for (; sig_list; sig_list = sig_list->next) {
7655 item = sig_list->data;
7657 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7658 if (g_signal_handler_is_connected(item->obj, item->sig))
7659 g_signal_handler_disconnect(item->obj, item->sig);
7662 MMPLAYER_FREEIF(item);
7665 g_list_free(player->signals[type]);
7666 player->signals[type] = NULL;
7674 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, unsigned int wl_surface_id)
7676 mmplayer_t *player = 0;
7677 int prev_display_surface_type = 0;
7681 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7683 player = MM_PLAYER_CAST(handle);
7685 /* check video sinkbin is created */
7686 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7687 LOGW("Videosink is already created");
7688 return MM_ERROR_NONE;
7691 LOGD("videosink element is not yet ready");
7693 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7694 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7696 return MM_ERROR_INVALID_ARGUMENT;
7699 /* load previous attributes */
7700 if (player->attrs) {
7701 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7702 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7703 if (prev_display_surface_type == surface_type) {
7704 LOGD("incoming display surface type is same as previous one, do nothing..");
7706 return MM_ERROR_NONE;
7709 LOGE("failed to load attributes");
7711 return MM_ERROR_PLAYER_INTERNAL;
7714 /* videobin is not created yet, so we just set attributes related to display surface */
7715 LOGD("store display attribute for given surface type(%d)", surface_type);
7716 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7717 "display_overlay", (int)wl_surface_id, NULL);
7720 return MM_ERROR_NONE;
7723 /* Note : if silent is true, then subtitle would not be displayed. :*/
7725 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7727 mmplayer_t *player = (mmplayer_t *)hplayer;
7731 /* check player handle */
7732 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7734 player->set_mode.subtitle_off = silent;
7736 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7740 return MM_ERROR_NONE;
7744 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7746 mmplayer_gst_element_t *mainbin = NULL;
7747 mmplayer_gst_element_t *textbin = NULL;
7748 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7749 GstState current_state = GST_STATE_VOID_PENDING;
7750 GstState element_state = GST_STATE_VOID_PENDING;
7751 GstState element_pending_state = GST_STATE_VOID_PENDING;
7753 GstEvent *event = NULL;
7754 int result = MM_ERROR_NONE;
7756 GstClock *curr_clock = NULL;
7757 GstClockTime base_time, start_time, curr_time;
7762 /* check player handle */
7763 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7765 player->pipeline->mainbin &&
7766 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7768 mainbin = player->pipeline->mainbin;
7769 textbin = player->pipeline->textbin;
7771 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7773 // sync clock with current pipeline
7774 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7775 curr_time = gst_clock_get_time(curr_clock);
7777 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7778 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7780 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7781 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7783 if (current_state > GST_STATE_READY) {
7784 // sync state with current pipeline
7785 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7786 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7787 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7789 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7790 if (GST_STATE_CHANGE_FAILURE == ret) {
7791 LOGE("fail to state change.");
7792 result = MM_ERROR_PLAYER_INTERNAL;
7796 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7797 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7800 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7801 gst_object_unref(curr_clock);
7804 // seek to current position
7805 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7806 result = MM_ERROR_PLAYER_INVALID_STATE;
7807 LOGE("gst_element_query_position failed, invalid state");
7811 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7812 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);
7814 _mmplayer_gst_send_event_to_sink(player, event);
7816 result = MM_ERROR_PLAYER_INTERNAL;
7817 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7821 /* sync state with current pipeline */
7822 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7823 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7824 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7826 return MM_ERROR_NONE;
7829 /* release text pipeline resource */
7830 player->textsink_linked = 0;
7832 /* release signal */
7833 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7835 /* release textbin with it's childs */
7836 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7837 MMPLAYER_FREEIF(player->pipeline->textbin);
7838 player->pipeline->textbin = NULL;
7840 /* release subtitle elem */
7841 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7842 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7848 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7850 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7851 GstState current_state = GST_STATE_VOID_PENDING;
7853 MMHandleType attrs = 0;
7854 mmplayer_gst_element_t *mainbin = NULL;
7855 mmplayer_gst_element_t *textbin = NULL;
7857 gchar *subtitle_uri = NULL;
7858 int result = MM_ERROR_NONE;
7859 const gchar *charset = NULL;
7863 /* check player handle */
7864 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7866 player->pipeline->mainbin &&
7867 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7868 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7870 mainbin = player->pipeline->mainbin;
7871 textbin = player->pipeline->textbin;
7873 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7874 if (current_state < GST_STATE_READY) {
7875 result = MM_ERROR_PLAYER_INVALID_STATE;
7876 LOGE("Pipeline is not in proper state");
7880 attrs = MMPLAYER_GET_ATTRS(player);
7882 LOGE("cannot get content attribute");
7883 result = MM_ERROR_PLAYER_INTERNAL;
7887 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7888 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7889 LOGE("subtitle uri is not proper filepath");
7890 result = MM_ERROR_PLAYER_INVALID_URI;
7894 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7895 LOGE("failed to get storage info of subtitle path");
7896 result = MM_ERROR_PLAYER_INVALID_URI;
7900 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
7901 SECURE_LOGD("new subtitle file path is [%s]", filepath);
7903 if (!strcmp(filepath, subtitle_uri)) {
7904 LOGD("subtitle path is not changed");
7907 if (mm_player_set_attribute((MMHandleType)player, NULL,
7908 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
7909 LOGE("failed to set attribute");
7914 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7915 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7916 player->subtitle_language_list = NULL;
7917 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7919 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7920 if (ret != GST_STATE_CHANGE_SUCCESS) {
7921 LOGE("failed to change state of textbin to READY");
7922 result = MM_ERROR_PLAYER_INTERNAL;
7926 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7927 if (ret != GST_STATE_CHANGE_SUCCESS) {
7928 LOGE("failed to change state of subparse to READY");
7929 result = MM_ERROR_PLAYER_INTERNAL;
7933 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7934 if (ret != GST_STATE_CHANGE_SUCCESS) {
7935 LOGE("failed to change state of filesrc to READY");
7936 result = MM_ERROR_PLAYER_INTERNAL;
7940 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7942 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7944 charset = _mmplayer_get_charset(filepath);
7946 LOGD("detected charset is %s", charset);
7947 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7950 result = _mmplayer_sync_subtitle_pipeline(player);
7957 /* API to switch between external subtitles */
7959 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7961 int result = MM_ERROR_NONE;
7962 mmplayer_t *player = (mmplayer_t *)hplayer;
7967 /* check player handle */
7968 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7970 /* filepath can be null in idle state */
7972 /* check file path */
7973 if ((path = strstr(filepath, "file://")))
7974 result = _mmplayer_exist_file_path(path + 7);
7976 result = _mmplayer_exist_file_path(filepath);
7978 if (result != MM_ERROR_NONE) {
7979 LOGE("invalid subtitle path 0x%X", result);
7980 return result; /* file not found or permission denied */
7984 if (!player->pipeline) {
7986 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
7987 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
7988 LOGE("failed to set attribute");
7989 return MM_ERROR_PLAYER_INTERNAL;
7992 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7993 /* check filepath */
7994 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7996 if (!__mmplayer_check_subtitle(player)) {
7997 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
7998 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
7999 LOGE("failed to set attribute");
8000 return MM_ERROR_PLAYER_INTERNAL;
8003 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8004 LOGE("fail to create text pipeline");
8005 return MM_ERROR_PLAYER_INTERNAL;
8008 result = _mmplayer_sync_subtitle_pipeline(player);
8010 result = __mmplayer_change_external_subtitle_language(player, filepath);
8013 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8014 player->is_external_subtitle_added_now = TRUE;
8016 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8017 if (!player->subtitle_language_list) {
8018 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8019 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8020 LOGW("subtitle language list is not updated yet");
8022 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8030 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8032 int result = MM_ERROR_NONE;
8033 gchar *change_pad_name = NULL;
8034 GstPad *sinkpad = NULL;
8035 mmplayer_gst_element_t *mainbin = NULL;
8036 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8037 GstCaps *caps = NULL;
8038 gint total_track_num = 0;
8042 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8043 MM_ERROR_PLAYER_NOT_INITIALIZED);
8045 LOGD("Change Track(%d) to %d", type, index);
8047 mainbin = player->pipeline->mainbin;
8049 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8050 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8051 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8052 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8054 /* Changing Video Track is not supported. */
8055 LOGE("Track Type Error");
8059 if (mainbin[elem_idx].gst == NULL) {
8060 result = MM_ERROR_PLAYER_NO_OP;
8061 LOGD("Req track doesn't exist");
8065 total_track_num = player->selector[type].total_track_num;
8066 if (total_track_num <= 0) {
8067 result = MM_ERROR_PLAYER_NO_OP;
8068 LOGD("Language list is not available");
8072 if ((index < 0) || (index >= total_track_num)) {
8073 result = MM_ERROR_INVALID_ARGUMENT;
8074 LOGD("Not a proper index : %d", index);
8078 /*To get the new pad from the selector*/
8079 change_pad_name = g_strdup_printf("sink_%u", index);
8080 if (change_pad_name == NULL) {
8081 result = MM_ERROR_PLAYER_INTERNAL;
8082 LOGD("Pad does not exists");
8086 LOGD("new active pad name: %s", change_pad_name);
8088 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8089 if (sinkpad == NULL) {
8090 LOGD("sinkpad is NULL");
8091 result = MM_ERROR_PLAYER_INTERNAL;
8095 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8096 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8098 caps = gst_pad_get_current_caps(sinkpad);
8099 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8102 gst_object_unref(sinkpad);
8104 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8105 __mmplayer_set_audio_attrs(player, caps);
8108 MMPLAYER_FREEIF(change_pad_name);
8113 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8115 int result = MM_ERROR_NONE;
8116 mmplayer_t *player = NULL;
8117 mmplayer_gst_element_t *mainbin = NULL;
8119 gint current_active_index = 0;
8121 GstState current_state = GST_STATE_VOID_PENDING;
8122 GstEvent *event = NULL;
8127 player = (mmplayer_t *)hplayer;
8128 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8130 if (!player->pipeline) {
8131 LOGE("Track %d pre setting -> %d", type, index);
8133 player->selector[type].active_pad_index = index;
8137 mainbin = player->pipeline->mainbin;
8139 current_active_index = player->selector[type].active_pad_index;
8141 /*If index is same as running index no need to change the pad*/
8142 if (current_active_index == index)
8145 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8146 result = MM_ERROR_PLAYER_INVALID_STATE;
8150 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8151 if (current_state < GST_STATE_PAUSED) {
8152 result = MM_ERROR_PLAYER_INVALID_STATE;
8153 LOGW("Pipeline not in porper state");
8157 result = __mmplayer_change_selector_pad(player, type, index);
8158 if (result != MM_ERROR_NONE) {
8159 LOGE("change selector pad error");
8163 player->selector[type].active_pad_index = index;
8165 if (current_state == GST_STATE_PLAYING) {
8166 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8167 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8168 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8170 _mmplayer_gst_send_event_to_sink(player, event);
8172 result = MM_ERROR_PLAYER_INTERNAL;
8182 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8184 mmplayer_t *player = (mmplayer_t *)hplayer;
8188 /* check player handle */
8189 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8191 *silent = player->set_mode.subtitle_off;
8193 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8197 return MM_ERROR_NONE;
8201 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8203 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8204 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8206 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8207 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8211 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8212 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8213 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8214 mmplayer_dump_t *dump_s;
8215 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8216 if (dump_s == NULL) {
8217 LOGE("malloc fail");
8221 dump_s->dump_element_file = NULL;
8222 dump_s->dump_pad = NULL;
8223 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8225 if (dump_s->dump_pad) {
8226 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8227 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]);
8228 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8229 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);
8230 /* add list for removed buffer probe and close FILE */
8231 player->dump_list = g_list_append(player->dump_list, dump_s);
8232 LOGD("%s sink pad added buffer probe for dump", factory_name);
8235 MMPLAYER_FREEIF(dump_s);
8236 LOGE("failed to get %s sink pad added", factory_name);
8243 static GstPadProbeReturn
8244 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8246 FILE *dump_data = (FILE *)u_data;
8248 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8249 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8251 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8253 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8255 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8257 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8259 gst_buffer_unmap(buffer, &probe_info);
8261 return GST_PAD_PROBE_OK;
8265 __mmplayer_release_dump_list(GList *dump_list)
8267 GList *d_list = dump_list;
8272 for (; d_list; d_list = g_list_next(d_list)) {
8273 mmplayer_dump_t *dump_s = d_list->data;
8274 if (dump_s->dump_pad) {
8275 if (dump_s->probe_handle_id)
8276 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8277 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8279 if (dump_s->dump_element_file) {
8280 fclose(dump_s->dump_element_file);
8281 dump_s->dump_element_file = NULL;
8283 MMPLAYER_FREEIF(dump_s);
8285 g_list_free(dump_list);
8290 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8292 mmplayer_t *player = (mmplayer_t *)hplayer;
8296 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8297 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8299 *exist = (bool)player->has_closed_caption;
8303 return MM_ERROR_NONE;
8307 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8312 LOGD("unref internal gst buffer %p", buffer);
8314 gst_buffer_unref((GstBuffer *)buffer);
8321 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8323 mmplayer_t *player = (mmplayer_t *)hplayer;
8327 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8328 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8330 if (MMPLAYER_IS_STREAMING(player))
8331 *timeout = (int)player->ini.live_state_change_timeout;
8333 *timeout = (int)player->ini.localplayback_state_change_timeout;
8335 LOGD("timeout = %d", *timeout);
8338 return MM_ERROR_NONE;
8342 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8346 MMPLAYER_RETURN_IF_FAIL(player);
8348 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8350 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8351 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8352 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8353 player->storage_info[i].id = -1;
8354 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8356 if (path_type != MMPLAYER_PATH_MAX)
8365 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8367 int ret = MM_ERROR_NONE;
8368 mmplayer_t *player = (mmplayer_t *)hplayer;
8369 MMMessageParamType msg_param = {0, };
8372 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8374 LOGW("state changed storage %d:%d", id, state);
8376 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8377 return MM_ERROR_NONE;
8379 /* FIXME: text path should be handled seperately. */
8380 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8381 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8382 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8383 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8384 LOGW("external storage is removed");
8386 if (player->msg_posted == FALSE) {
8387 memset(&msg_param, 0, sizeof(MMMessageParamType));
8388 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8389 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8390 player->msg_posted = TRUE;
8393 /* unrealize the player */
8394 ret = _mmplayer_unrealize(hplayer);
8395 if (ret != MM_ERROR_NONE)
8396 LOGE("failed to unrealize");
8404 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8406 int ret = MM_ERROR_NONE;
8407 mmplayer_t *player = (mmplayer_t *)hplayer;
8408 int idx = 0, total = 0;
8409 gchar *result = NULL, *tmp = NULL;
8412 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8413 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8415 total = *num = g_list_length(player->adaptive_info.var_list);
8417 LOGW("There is no stream variant info.");
8421 result = g_strdup("");
8422 for (idx = 0 ; idx < total ; idx++) {
8423 stream_variant_t *v_data = NULL;
8424 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8427 gchar data[64] = {0};
8428 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8430 tmp = g_strconcat(result, data, NULL);
8434 LOGW("There is no variant data in %d", idx);
8439 *var_info = (char *)result;
8441 LOGD("variant info %d:%s", *num, *var_info);
8447 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8449 int ret = MM_ERROR_NONE;
8450 mmplayer_t *player = (mmplayer_t *)hplayer;
8453 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8455 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8457 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8458 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8459 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8461 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8462 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8463 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8464 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8466 /* FIXME: seek to current position for applying new variant limitation */
8475 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8477 int ret = MM_ERROR_NONE;
8478 mmplayer_t *player = (mmplayer_t *)hplayer;
8481 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8482 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8484 *bandwidth = player->adaptive_info.limit.bandwidth;
8485 *width = player->adaptive_info.limit.width;
8486 *height = player->adaptive_info.limit.height;
8488 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8495 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8497 int ret = MM_ERROR_NONE;
8498 mmplayer_t *player = (mmplayer_t *)hplayer;
8501 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8502 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8503 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8505 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8507 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8508 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8509 else /* live case */
8510 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8512 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8519 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8521 #define IDX_FIRST_SW_CODEC 0
8522 mmplayer_t *player = (mmplayer_t *)hplayer;
8523 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8526 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8528 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8529 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8530 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8532 switch (stream_type) {
8533 case MM_PLAYER_STREAM_TYPE_AUDIO:
8534 /* to support audio codec selection, codec info have to be added in ini file as below.
8535 audio codec element hw = xxxx
8536 audio codec element sw = avdec */
8537 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8538 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8539 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8540 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8541 LOGE("There is no audio codec info for codec_type %d", codec_type);
8542 return MM_ERROR_PLAYER_NO_OP;
8545 case MM_PLAYER_STREAM_TYPE_VIDEO:
8546 /* to support video codec selection, codec info have to be added in ini file as below.
8547 video codec element hw = omx
8548 video codec element sw = avdec */
8549 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8550 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8551 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8552 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8553 LOGE("There is no video codec info for codec_type %d", codec_type);
8554 return MM_ERROR_PLAYER_NO_OP;
8558 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8559 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8563 LOGD("update %s codec_type to %d", attr_name, codec_type);
8564 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8567 return MM_ERROR_NONE;
8571 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8573 mmplayer_t *player = (mmplayer_t *)hplayer;
8574 GstElement *rg_vol_element = NULL;
8578 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8580 player->sound.rg_enable = enabled;
8582 /* just hold rgvolume enable value if pipeline is not ready */
8583 if (!player->pipeline || !player->pipeline->audiobin) {
8584 LOGD("pipeline is not ready. holding rgvolume enable value");
8585 return MM_ERROR_NONE;
8588 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8590 if (!rg_vol_element) {
8591 LOGD("rgvolume element is not created");
8592 return MM_ERROR_PLAYER_INTERNAL;
8596 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8598 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8602 return MM_ERROR_NONE;
8606 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8608 mmplayer_t *player = (mmplayer_t *)hplayer;
8609 GstElement *rg_vol_element = NULL;
8610 gboolean enable = FALSE;
8614 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8615 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8617 /* just hold enable_rg value if pipeline is not ready */
8618 if (!player->pipeline || !player->pipeline->audiobin) {
8619 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8620 *enabled = player->sound.rg_enable;
8621 return MM_ERROR_NONE;
8624 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8626 if (!rg_vol_element) {
8627 LOGD("rgvolume element is not created");
8628 return MM_ERROR_PLAYER_INTERNAL;
8631 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8632 *enabled = (bool)enable;
8636 return MM_ERROR_NONE;
8640 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8642 mmplayer_t *player = (mmplayer_t *)hplayer;
8643 MMHandleType attrs = 0;
8645 int ret = MM_ERROR_NONE;
8649 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8651 attrs = MMPLAYER_GET_ATTRS(player);
8652 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8654 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
8656 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8657 return MM_ERROR_PLAYER_INTERNAL;
8660 player->video_roi.scale_x = scale_x;
8661 player->video_roi.scale_y = scale_y;
8662 player->video_roi.scale_width = scale_width;
8663 player->video_roi.scale_height = scale_height;
8665 /* check video sinkbin is created */
8666 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8667 return MM_ERROR_NONE;
8669 if (!gst_video_overlay_set_video_roi_area(
8670 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8671 scale_x, scale_y, scale_width, scale_height))
8672 ret = MM_ERROR_PLAYER_INTERNAL;
8674 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8675 scale_x, scale_y, scale_width, scale_height);
8683 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8685 mmplayer_t *player = (mmplayer_t *)hplayer;
8686 int ret = MM_ERROR_NONE;
8690 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8691 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8693 *scale_x = player->video_roi.scale_x;
8694 *scale_y = player->video_roi.scale_y;
8695 *scale_width = player->video_roi.scale_width;
8696 *scale_height = player->video_roi.scale_height;
8698 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8699 *scale_x, *scale_y, *scale_width, *scale_height);
8705 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8707 mmplayer_t* player = (mmplayer_t*)hplayer;
8711 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8713 player->client_pid = pid;
8715 LOGD("client pid[%d] %p", pid, player);
8719 return MM_ERROR_NONE;
8723 __mmplayer_update_duration_value(mmplayer_t *player)
8725 gboolean ret = FALSE;
8726 gint64 dur_nsec = 0;
8727 LOGD("try to update duration");
8729 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8730 player->duration = dur_nsec;
8731 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8735 if (player->duration < 0) {
8736 LOGW("duration is Non-Initialized !!!");
8737 player->duration = 0;
8740 /* update streaming service type */
8741 player->streaming_type = _mmplayer_get_stream_service_type(player);
8743 /* check duration is OK */
8744 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8745 /* FIXIT : find another way to get duration here. */
8746 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8752 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8754 /* update audio params
8755 NOTE : We need original audio params and it can be only obtained from src pad of audio
8756 decoder. Below code only valid when we are not using 'resampler' just before
8757 'audioconverter'. */
8758 GstCaps *caps_a = NULL;
8760 gint samplerate = 0, channels = 0;
8761 GstStructure *p = NULL;
8762 GstElement *aconv = NULL;
8764 LOGD("try to update audio attrs");
8766 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8768 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8769 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8770 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8771 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8773 LOGE("there is no audio converter");
8777 pad = gst_element_get_static_pad(aconv, "sink");
8780 LOGW("failed to get pad from audio converter");
8784 caps_a = gst_pad_get_current_caps(pad);
8786 LOGW("not ready to get audio caps");
8787 gst_object_unref(pad);
8791 p = gst_caps_get_structure(caps_a, 0);
8793 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8795 gst_structure_get_int(p, "rate", &samplerate);
8796 gst_structure_get_int(p, "channels", &channels);
8798 mm_player_set_attribute((MMHandleType)player, NULL,
8799 "content_audio_samplerate", samplerate,
8800 "content_audio_channels", channels, NULL);
8802 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8804 gst_caps_unref(caps_a);
8805 gst_object_unref(pad);
8811 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8813 LOGD("try to update video attrs");
8815 GstCaps *caps_v = NULL;
8819 GstStructure *p = NULL;
8821 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8822 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8824 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8826 LOGD("no videosink sink pad");
8830 caps_v = gst_pad_get_current_caps(pad);
8831 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8832 if (!caps_v && player->v_stream_caps) {
8833 caps_v = player->v_stream_caps;
8834 gst_caps_ref(caps_v);
8838 LOGD("no negitiated caps from videosink");
8839 gst_object_unref(pad);
8843 p = gst_caps_get_structure(caps_v, 0);
8844 gst_structure_get_int(p, "width", &width);
8845 gst_structure_get_int(p, "height", &height);
8847 mm_player_set_attribute((MMHandleType)player, NULL,
8848 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
8850 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8852 SECURE_LOGD("width : %d height : %d", width, height);
8854 gst_caps_unref(caps_v);
8855 gst_object_unref(pad);
8858 mm_player_set_attribute((MMHandleType)player, NULL,
8859 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
8860 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8867 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8869 gboolean ret = FALSE;
8870 guint64 data_size = 0;
8874 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8875 if (!player->duration)
8878 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8879 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8880 if (stat(path, &sb) == 0)
8881 data_size = (guint64)sb.st_size;
8883 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8884 data_size = player->http_content_size;
8887 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8890 guint64 bitrate = 0;
8891 guint64 msec_dur = 0;
8893 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8895 bitrate = data_size * 8 * 1000 / msec_dur;
8896 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
8897 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8898 mm_player_set_attribute((MMHandleType)player, NULL,
8899 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
8902 LOGD("player duration is less than 0");
8906 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8907 if (player->total_bitrate) {
8908 mm_player_set_attribute((MMHandleType)player, NULL,
8909 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
8918 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8920 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8921 data->uri_type = uri_type;
8925 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
8927 int ret = MM_ERROR_PLAYER_INVALID_URI;
8929 char *buffer = NULL;
8930 char *seperator = strchr(path, ',');
8931 char ext[100] = {0,}, size[100] = {0,};
8934 if ((buffer = strstr(path, "ext="))) {
8935 buffer += strlen("ext=");
8937 if (strlen(buffer)) {
8938 strncpy(ext, buffer, 99);
8940 if ((seperator = strchr(ext, ','))
8941 || (seperator = strchr(ext, ' '))
8942 || (seperator = strchr(ext, '\0'))) {
8943 seperator[0] = '\0';
8948 if ((buffer = strstr(path, "size="))) {
8949 buffer += strlen("size=");
8951 if (strlen(buffer) > 0) {
8952 strncpy(size, buffer, 99);
8954 if ((seperator = strchr(size, ','))
8955 || (seperator = strchr(size, ' '))
8956 || (seperator = strchr(size, '\0'))) {
8957 seperator[0] = '\0';
8960 mem_size = atoi(size);
8965 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8967 if (mem_size && param) {
8968 if (data->input_mem.buf)
8969 free(data->input_mem.buf);
8970 data->input_mem.buf = malloc(mem_size);
8972 if (data->input_mem.buf) {
8973 memcpy(data->input_mem.buf, param, mem_size);
8974 data->input_mem.len = mem_size;
8975 ret = MM_ERROR_NONE;
8977 LOGE("failed to alloc mem %d", mem_size);
8978 ret = MM_ERROR_PLAYER_INTERNAL;
8981 data->input_mem.offset = 0;
8982 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8989 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
8991 gchar *location = NULL;
8994 int ret = MM_ERROR_NONE;
8996 if ((path = strstr(uri, "file://"))) {
8997 location = g_filename_from_uri(uri, NULL, &err);
8998 if (!location || (err != NULL)) {
8999 LOGE("Invalid URI '%s' for filesrc: %s", path,
9000 (err != NULL) ? err->message : "unknown error");
9004 MMPLAYER_FREEIF(location);
9006 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9007 return MM_ERROR_PLAYER_INVALID_URI;
9009 LOGD("path from uri: %s", location);
9012 path = (location != NULL) ? (location) : ((char *)uri);
9015 ret = _mmplayer_exist_file_path(path);
9017 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9018 if (ret == MM_ERROR_NONE) {
9019 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9020 if (_mmplayer_is_sdp_file(path)) {
9021 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9022 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9024 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9026 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9027 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9029 LOGE("invalid uri, could not play..");
9030 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9033 MMPLAYER_FREEIF(location);
9038 static mmplayer_video_decoded_data_info_t *
9039 __mmplayer_create_stream_from_pad(GstPad *pad)
9041 GstCaps *caps = NULL;
9042 GstStructure *structure = NULL;
9043 unsigned int fourcc = 0;
9044 const gchar *string_format = NULL;
9045 mmplayer_video_decoded_data_info_t *stream = NULL;
9047 MMPixelFormatType format;
9050 caps = gst_pad_get_current_caps(pad);
9052 LOGE("Caps is NULL.");
9057 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9059 structure = gst_caps_get_structure(caps, 0);
9060 gst_structure_get_int(structure, "width", &width);
9061 gst_structure_get_int(structure, "height", &height);
9062 string_format = gst_structure_get_string(structure, "format");
9065 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9066 format = _mmplayer_get_pixtype(fourcc);
9067 gst_video_info_from_caps(&info, caps);
9068 gst_caps_unref(caps);
9071 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9072 LOGE("Wrong condition!!");
9076 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9078 LOGE("failed to alloc mem for video data");
9082 stream->width = width;
9083 stream->height = height;
9084 stream->format = format;
9085 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9091 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9093 unsigned int pitch = 0;
9094 unsigned int size = 0;
9096 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9099 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9100 bo = gst_tizen_memory_get_bos(mem, index);
9102 stream->bo[index] = tbm_bo_ref(bo);
9104 LOGE("failed to get bo for index %d", index);
9107 for (index = 0; index < stream->plane_num; index++) {
9108 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9109 stream->stride[index] = pitch;
9111 stream->elevation[index] = size / pitch;
9113 stream->elevation[index] = stream->height;
9118 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9120 if (stream->format == MM_PIXEL_FORMAT_I420) {
9121 int ret = TBM_SURFACE_ERROR_NONE;
9122 tbm_surface_h surface;
9123 tbm_surface_info_s info;
9125 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9127 ret = tbm_surface_get_info(surface, &info);
9128 if (ret != TBM_SURFACE_ERROR_NONE) {
9129 tbm_surface_destroy(surface);
9133 tbm_surface_destroy(surface);
9134 stream->stride[0] = info.planes[0].stride;
9135 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9136 stream->stride[1] = info.planes[1].stride;
9137 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9138 stream->stride[2] = info.planes[2].stride;
9139 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9140 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9141 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9142 stream->stride[0] = stream->width * 4;
9143 stream->elevation[0] = stream->height;
9144 stream->bo_size = stream->stride[0] * stream->height;
9146 LOGE("Not support format %d", stream->format);
9154 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9156 tbm_bo_handle thandle;
9158 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9159 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9160 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9164 unsigned char *src = NULL;
9165 unsigned char *dest = NULL;
9166 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9168 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9170 LOGE("fail to gst_memory_map");
9174 if (!mapinfo.data) {
9175 LOGE("data pointer is wrong");
9179 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9180 if (!stream->bo[0]) {
9181 LOGE("Fail to tbm_bo_alloc!!");
9185 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9187 LOGE("thandle pointer is wrong");
9191 if (stream->format == MM_PIXEL_FORMAT_I420) {
9192 src_stride[0] = GST_ROUND_UP_4(stream->width);
9193 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9194 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9195 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9198 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9199 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9201 for (i = 0; i < 3; i++) {
9202 src = mapinfo.data + src_offset[i];
9203 dest = thandle.ptr + dest_offset[i];
9208 for (j = 0; j < stream->height >> k; j++) {
9209 memcpy(dest, src, stream->width>>k);
9210 src += src_stride[i];
9211 dest += stream->stride[i];
9214 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9215 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9217 LOGE("Not support format %d", stream->format);
9221 tbm_bo_unmap(stream->bo[0]);
9222 gst_memory_unmap(mem, &mapinfo);
9228 tbm_bo_unmap(stream->bo[0]);
9231 gst_memory_unmap(mem, &mapinfo);
9237 __mmplayer_set_pause_state(mmplayer_t *player)
9239 if (player->sent_bos)
9242 /* rtsp case, get content attrs by GstMessage */
9243 if (MMPLAYER_IS_RTSP_STREAMING(player))
9246 /* it's first time to update all content attrs. */
9247 _mmplayer_update_content_attrs(player, ATTR_ALL);
9251 __mmplayer_set_playing_state(mmplayer_t *player)
9253 gchar *audio_codec = NULL;
9255 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9256 /* initialize because auto resume is done well. */
9257 player->resumed_by_rewind = FALSE;
9258 player->playback_rate = 1.0;
9261 if (player->sent_bos)
9264 /* try to get content metadata */
9266 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9267 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9268 * legacy mmfw-player api
9270 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9272 if ((player->cmd == MMPLAYER_COMMAND_START)
9273 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9274 __mmplayer_handle_missed_plugin(player);
9277 /* check audio codec field is set or not
9278 * we can get it from typefinder or codec's caps.
9280 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9282 /* The codec format can't be sent for audio only case like amr, mid etc.
9283 * Because, parser don't make related TAG.
9284 * So, if it's not set yet, fill it with found data.
9287 if (g_strrstr(player->type, "audio/midi"))
9288 audio_codec = "MIDI";
9289 else if (g_strrstr(player->type, "audio/x-amr"))
9290 audio_codec = "AMR";
9291 else if (g_strrstr(player->type, "audio/mpeg")
9292 && !g_strrstr(player->type, "mpegversion=(int)1"))
9293 audio_codec = "AAC";
9295 audio_codec = "unknown";
9297 if (mm_player_set_attribute((MMHandleType)player, NULL,
9298 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9299 LOGE("failed to set attribute");
9301 LOGD("set audio codec type with caps");